From 16b7e4a7ef473a6af29ec78aeb2f471fa398efdd Mon Sep 17 00:00:00 2001
From: leesam <leesam@leesam.cn>
Date: 星期三, 10 四月 2024 20:49:44 +0800
Subject: [PATCH] Merge branch 'refs/heads/master' into develop-add-api-key

---
 src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java                                 |   19 
 web_src/src/components/service/MediaServer.js                                                                                   |    3 
 src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java                                                  |    6 
 src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java                                                                      |   34 
 src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java                                                            |   13 
 src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java                                                           |   15 
 src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java                                                        |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java                    |   32 
 src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java                                                               |    8 
 src/main/java/com/genersoft/iot/vmp/media/event/media/MediaPublishEvent.java                                                    |   33 
 src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java                                                            |   10 
 src/main/java/com/genersoft/iot/vmp/conf/CloudRecordTimer.java                                                                  |   22 
 src/main/java/com/genersoft/iot/vmp/service/IPlayService.java                                                                   |   23 
 src/main/java/com/genersoft/iot/vmp/media/bean/RecordInfo.java                                                                  |   92 
 src/main/java/com/genersoft/iot/vmp/media/event/media/MediaNotFoundEvent.java                                                   |   22 
 src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java                                                       |  129 
 src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerEventAbstract.java                                       |    7 
 src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java                                                           |  554 ++--
 src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java                                                            |   15 
 src/main/java/com/genersoft/iot/vmp/media/event/media/MediaDepartureEvent.java                                                  |   22 
 src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerOfflineEvent.java                                        |   11 
 src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java                                             |    9 
 src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java                                             |   18 
 src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java                                                                |   24 
 src/main/java/com/genersoft/iot/vmp/media/event/media/MediaRecordMp4Event.java                                                  |   35 
 src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java                                                     |  278 +
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java                                                 |   81 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManger.java                                                   |  306 ++
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java                                                              |   70 
 pom.xml                                                                                                                         |    2 
 web_src/src/components/dialog/MediaServerEdit.vue                                                                               |   11 
 src/main/java/com/genersoft/iot/vmp/media/bean/ResultForOnPublish.java                                                          |   59 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamAuthorityInfo.java                                                      |   25 
 src/main/java/com/genersoft/iot/vmp/media/bean/MediaInfo.java                                                                   |  306 ++
 src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java                                  |   25 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java                                                          |    2 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java                                                          |    4 
 src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java                                                            |    8 
 src/main/java/com/genersoft/iot/vmp/media/event/hook/HookSubscribe.java                                                         |  107 
 src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java                                                            |   14 
 src/main/java/com/genersoft/iot/vmp/utils/CloudRecordUtils.java                                                                 |    4 
 src/main/java/com/genersoft/iot/vmp/media/event/hook/HookData.java                                                              |  132 +
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java                                |   88 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java                                                          |  749 -----
 web_src/static/images/abl-logo.jpg                                                                                              |    0 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java                                      |   29 
 src/main/java/com/genersoft/iot/vmp/service/bean/ResponseSendItemMsg.java                                                       |    8 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java                                                   |   75 
 src/main/java/com/genersoft/iot/vmp/media/event/hook/HookType.java                                                              |   15 
 src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerOnlineEvent.java                                         |   11 
 src/main/java/com/genersoft/iot/vmp/media/MediaServerConfig.java                                                                |   64 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java                                                 |   14 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java                                                    |  349 ++
 src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java                                                             |   55 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java                                                     |   16 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookParam.java                                                           |    2 
 src/main/java/com/genersoft/iot/vmp/media/event/media/MediaEvent.java                                                           |   56 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java                                |   11 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java                                          |    8 
 src/main/java/com/genersoft/iot/vmp/media/service/IMediaServerService.java                                                      |  145 +
 数据库/2.7.1/更新-postgresql-kingbase-2.7.0.sql                                                                                      |   11 
 src/main/java/com/genersoft/iot/vmp/media/event/hook/Hook.java                                                                  |   86 
 src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java                                                   |   34 
 src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java                                                |   35 
 src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerChangeEvent.java                                         |   34 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java                                                           |   43 
 数据库/2.7.1/初始化-postgresql-kingbase-2.7.0.sql                                                                                     |    6 
 src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java                                               |    4 
 src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java                                              |  837 ++++++
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java |   13 
 数据库/2.7.1/更新-mysql-2.7.0.sql                                                                                                    |   11 
 src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java                                                           |    4 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java                             |   72 
 数据库/2.7.1/初始化-mysql-2.7.0.sql                                                                                                   |    6 
 src/main/java/com/genersoft/iot/vmp/media/zlm/event/HookZlmServerKeepaliveEvent.java                                            |   24 
 src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java                                                                 |   68 
 src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java                                                           |   19 
 src/main/java/com/genersoft/iot/vmp/conf/WVPTimerTask.java                                                                      |    4 
 src/main/java/com/genersoft/iot/vmp/media/event/media/MediaRtpServerTimeoutEvent.java                                           |   22 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java                                                          |   17 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java                                                             |   35 
 src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java                                                             |    5 
 src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java                                                    |   35 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java                                            |    6 
 src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java                                  |    2 
 src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java                                                        |    4 
 src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java                                                  |    5 
 src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java                                                          |  370 ++
 src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java                                                           |   12 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java                                              |   13 
 src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java                                                    |   17 
 src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java                                                               |   49 
 src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java                                                                       |   98 
 web_src/src/components/MediaServerManger.vue                                                                                    |   10 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamInfo.java                                                          |   10 
 src/main/java/com/genersoft/iot/vmp/media/zlm/event/HookZlmServerStartEvent.java                                                |   24 
 src/main/java/com/genersoft/iot/vmp/service/IMediaService.java                                                                  |   37 
 src/main/java/com/genersoft/iot/vmp/media/service/IMediaNodeServerService.java                                                  |   61 
 src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java                                                           |    5 
 src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java                                                         |   17 
 src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java                                                                 |   20 
 src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaSendRtpStoppedEvent.java                                       |   52 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java                                                       |   10 
 src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java                                                       |   39 
 /dev/null                                                                                                                       |  756 -----
 src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java                                                         |   38 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java   |   31 
 src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerDeleteEvent.java                                         |   11 
 src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java                                                    |   46 
 src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java                                                    |  271 +-
 110 files changed, 4,940 insertions(+), 2,786 deletions(-)

diff --git a/pom.xml b/pom.xml
index f38d693..e129b78 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
 
     <groupId>com.genersoft</groupId>
     <artifactId>wvp-pro</artifactId>
-    <version>2.7.0</version>
+    <version>2.7.1</version>
     <name>web video platform</name>
     <description>鍥芥爣28181瑙嗛骞冲彴</description>
     <packaging>${project.packaging}</packaging>
diff --git a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
index 979f54a..f477439 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.common;
 
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
 import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
 import io.swagger.v3.oas.annotations.media.Schema;
 
@@ -70,7 +71,7 @@
     @Schema(description = "娴佸獟浣揑D")
     private String mediaServerId;
     @Schema(description = "娴佺紪鐮佷俊鎭�")
-    private Object tracks;
+    private MediaInfo mediaInfo;
     @Schema(description = "寮�濮嬫椂闂�")
     private String startTime;
     @Schema(description = "缁撴潫鏃堕棿")
@@ -82,6 +83,9 @@
 
     @Schema(description = "鏄惁鏆傚仠锛堝綍鍍忓洖鏀句娇鐢級")
     private boolean pause;
+
+    @Schema(description = "浜х敓婧愮被鍨嬶紝鍖呮嫭 unknown = 0,rtmp_push=1,rtsp_push=2,rtp_push=3,pull=4,ffmpeg_pull=5,mp4_vod=6,device_chn=7")
+    private int originType;
 
     public void setFlv(StreamURL flv) {
         this.flv = flv;
@@ -191,14 +195,22 @@
         }
     }
 
-    public void setFlv(String host, int port, int sslPort, String app, String stream, String callIdParam) {
-        String file = String.format("%s/%s.live.flv%s", app, stream, callIdParam);
+    public void setFlv(String host, int port, int sslPort, String file) {
         if (port > 0) {
             this.flv = new StreamURL("http", host, port, file);
         }
         this.ws_flv = new StreamURL("ws", host, port, file);
         if (sslPort > 0) {
             this.https_flv = new StreamURL("https", host, sslPort, file);
+            this.wss_flv = new StreamURL("wss", host, sslPort, file);
+        }
+    }
+
+    public void setWsFlv(String host, int port, int sslPort, String file) {
+        if (port > 0) {
+            this.ws_flv = new StreamURL("ws", host, port, file);
+        }
+        if (sslPort > 0) {
             this.wss_flv = new StreamURL("wss", host, sslPort, file);
         }
     }
@@ -473,12 +485,12 @@
         this.mediaServerId = mediaServerId;
     }
 
-    public Object getTracks() {
-        return tracks;
+    public MediaInfo getMediaInfo() {
+        return mediaInfo;
     }
 
-    public void setTracks(Object tracks) {
-        this.tracks = tracks;
+    public void setMediaInfo(MediaInfo mediaInfo) {
+        this.mediaInfo = mediaInfo;
     }
 
     public String getStartTime() {
@@ -615,4 +627,12 @@
     public void setDownLoadFilePath(DownloadFileInfo downLoadFilePath) {
         this.downLoadFilePath = downLoadFilePath;
     }
+
+    public int getOriginType() {
+        return originType;
+    }
+
+    public void setOriginType(int originType) {
+        this.originType = originType;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
index d19b8f0..df230d4 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -12,9 +12,9 @@
 
 	public static final String WVP_SERVER_STREAM_PREFIX = "VMP_SIGNALLING_STREAM_";
 
-	public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_";
+	public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER:";
 
-	public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_";
+	public static final String ONLINE_MEDIA_SERVERS_PREFIX = "VMP_ONLINE_MEDIA_SERVERS:";
 
 	public static final String DEVICE_PREFIX = "VMP_DEVICE_";
 
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/CloudRecordTimer.java b/src/main/java/com/genersoft/iot/vmp/conf/CloudRecordTimer.java
index f98977f..de87a9c 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/CloudRecordTimer.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/CloudRecordTimer.java
@@ -1,14 +1,10 @@
 package com.genersoft.iot.vmp.conf;
 
 
-import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
-import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
 import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper;
-import com.genersoft.iot.vmp.vmanager.cloudRecord.CloudRecordController;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -16,7 +12,6 @@
 import org.springframework.stereotype.Component;
 
 import java.io.File;
-import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
@@ -35,9 +30,6 @@
     @Autowired
     private CloudRecordServiceMapper cloudRecordServiceMapper;
 
-    @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
-
     /**
      * 瀹氭椂鏌ヨ寰呭垹闄ょ殑褰曞儚鏂囦欢
      */
@@ -46,12 +38,12 @@
     public void execute(){
         logger.info("[褰曞儚鏂囦欢瀹氭椂娓呯悊] 寮�濮嬫竻鐞嗚繃鏈熷綍鍍忔枃浠�");
         // 鑾峰彇閰嶇疆浜哸ssist鐨勬祦濯掍綋鑺傜偣
-        List<MediaServerItem> mediaServerItemList =  mediaServerService.getAllOnline();
+        List<MediaServer> mediaServerItemList =  mediaServerService.getAllOnline();
         if (mediaServerItemList.isEmpty()) {
             return;
         }
         long result = 0;
-        for (MediaServerItem mediaServerItem : mediaServerItemList) {
+        for (MediaServer mediaServerItem : mediaServerItemList) {
 
             Calendar lastCalendar = Calendar.getInstance();
             if (mediaServerItem.getRecordDay() > 0) {
@@ -69,10 +61,10 @@
                 // TODO 鍚庣画鍙互鍒犻櫎绌轰簡鐨勮繃鏈熸棩鏈熸枃浠跺す
                 for (CloudRecordItem cloudRecordItem : cloudRecordItemList) {
                     String date = new File(cloudRecordItem.getFilePath()).getParentFile().getName();
-                    JSONObject jsonObject = zlmresTfulUtils.deleteRecordDirectory(mediaServerItem, cloudRecordItem.getApp(),
+                    boolean deleteResult = mediaServerService.deleteRecordDirectory(mediaServerItem, cloudRecordItem.getApp(),
                             cloudRecordItem.getStream(), date, cloudRecordItem.getFileName());
-                    if (jsonObject.getInteger("code") != 0) {
-                        logger.warn("[褰曞儚鏂囦欢瀹氭椂娓呯悊] 鍒犻櫎纾佺洏鏂囦欢閿欒锛� {}:{}", cloudRecordItem.getFilePath(), jsonObject);
+                    if (deleteResult) {
+                        logger.warn("[褰曞儚鏂囦欢瀹氭椂娓呯悊] 鍒犻櫎纾佺洏鏂囦欢鎴愬姛锛� {}", cloudRecordItem.getFilePath());
                     }
                 }
                 result += cloudRecordServiceMapper.deleteList(cloudRecordItemList);
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
index 884036a..eac7c11 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
@@ -1,6 +1,6 @@
 package com.genersoft.iot.vmp.conf;
 
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,11 +42,23 @@
     @Value("${media.stream-ip:${media.ip}}")
     private String streamIp;
 
-    @Value("${media.http-port}")
+    @Value("${media.http-port:0}")
     private Integer httpPort;
+
+    @Value("${media.flv-port:0}")
+    private Integer flvPort = 0;
+
+    @Value("${media.ws-flv-port:0}")
+    private Integer wsFlvPort = 0;
 
     @Value("${media.http-ssl-port:0}")
     private Integer httpSSlPort = 0;
+
+    @Value("${media.flv-ssl-port:0}")
+    private Integer flvSSlPort = 0;
+
+    @Value("${media.ws-flv-ssl-port:0}")
+    private Integer wsFlvSSlPort = 0;
 
     @Value("${media.rtmp-port:0}")
     private Integer rtmpPort = 0;
@@ -86,6 +98,9 @@
 
     @Value("${media.record-path:}")
     private String recordPath;
+
+    @Value("${media.type:zlm}")
+    private String type;
 
     public String getId() {
         return id;
@@ -196,36 +211,59 @@
         return sipDomain;
     }
 
-    public MediaServerItem getMediaSerItem(){
-        MediaServerItem mediaServerItem = new MediaServerItem();
-        mediaServerItem.setId(id);
-        mediaServerItem.setIp(ip);
-        mediaServerItem.setDefaultServer(true);
-        mediaServerItem.setHookIp(getHookIp());
-        mediaServerItem.setSdpIp(getSdpIp());
-        mediaServerItem.setStreamIp(getStreamIp());
-        mediaServerItem.setHttpPort(httpPort);
-        mediaServerItem.setHttpSSlPort(httpSSlPort);
-        mediaServerItem.setRtmpPort(rtmpPort);
-        mediaServerItem.setRtmpSSlPort(rtmpSSlPort);
-        mediaServerItem.setRtpProxyPort(getRtpProxyPort());
-        mediaServerItem.setRtspPort(rtspPort);
-        mediaServerItem.setRtspSSLPort(rtspSSLPort);
-        mediaServerItem.setAutoConfig(autoConfig);
-        mediaServerItem.setSecret(secret);
-        mediaServerItem.setRtpEnable(rtpEnable);
-        mediaServerItem.setRtpPortRange(rtpPortRange);
-        mediaServerItem.setSendRtpPortRange(rtpSendPortRange);
-        mediaServerItem.setRecordAssistPort(recordAssistPort);
-        mediaServerItem.setHookAliveInterval(30.00f);
-        mediaServerItem.setRecordDay(recordDay);
-        if (recordPath != null) {
-            mediaServerItem.setRecordPath(recordPath);
+    public MediaServer getMediaSerItem(){
+        MediaServer mediaServer = new MediaServer();
+        mediaServer.setId(id);
+        mediaServer.setIp(ip);
+        mediaServer.setDefaultServer(true);
+        mediaServer.setHookIp(getHookIp());
+        mediaServer.setSdpIp(getSdpIp());
+        mediaServer.setStreamIp(getStreamIp());
+        mediaServer.setHttpPort(httpPort);
+        if (flvPort == 0) {
+            mediaServer.setFlvPort(httpPort);
+        }else {
+            mediaServer.setFlvPort(flvPort);
         }
-        mediaServerItem.setCreateTime(DateUtil.getNow());
-        mediaServerItem.setUpdateTime(DateUtil.getNow());
+        if (wsFlvPort == 0) {
+            mediaServer.setWsFlvPort(httpPort);
+        }else {
+            mediaServer.setWsFlvPort(wsFlvPort);
+        }
+        if (flvSSlPort == 0) {
+            mediaServer.setFlvSSLPort(httpSSlPort);
+        }else {
+            mediaServer.setFlvSSLPort(flvSSlPort);
+        }
+        if (wsFlvSSlPort == 0) {
+            mediaServer.setWsFlvSSLPort(httpSSlPort);
+        }else {
+            mediaServer.setWsFlvSSLPort(wsFlvSSlPort);
+        }
 
-        return mediaServerItem;
+        mediaServer.setHttpSSlPort(httpSSlPort);
+        mediaServer.setRtmpPort(rtmpPort);
+        mediaServer.setRtmpSSlPort(rtmpSSlPort);
+        mediaServer.setRtpProxyPort(getRtpProxyPort());
+        mediaServer.setRtspPort(rtspPort);
+        mediaServer.setRtspSSLPort(rtspSSLPort);
+        mediaServer.setAutoConfig(autoConfig);
+        mediaServer.setSecret(secret);
+        mediaServer.setRtpEnable(rtpEnable);
+        mediaServer.setRtpPortRange(rtpPortRange);
+        mediaServer.setSendRtpPortRange(rtpSendPortRange);
+        mediaServer.setRecordAssistPort(recordAssistPort);
+        mediaServer.setHookAliveInterval(10f);
+        mediaServer.setRecordDay(recordDay);
+        mediaServer.setStatus(false);
+        mediaServer.setType(type);
+        if (recordPath != null) {
+            mediaServer.setRecordPath(recordPath);
+        }
+        mediaServer.setCreateTime(DateUtil.getNow());
+        mediaServer.setUpdateTime(DateUtil.getNow());
+
+        return mediaServer;
     }
 
     public Integer getRecordDay() {
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
index a7416a8..3948fdb 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
@@ -1,7 +1,7 @@
 package com.genersoft.iot.vmp.conf;
 
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
@@ -54,7 +54,7 @@
         @Override
         protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
             String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
-            MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
+            MediaServer mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
             if (mediaInfo != null) {
                 if (!ObjectUtils.isEmpty(queryStr)) {
                     queryStr += "&secret=" + mediaInfo.getSecret();
@@ -103,7 +103,7 @@
         @Override
         protected String getTargetUri(HttpServletRequest servletRequest) {
             String requestURI = servletRequest.getRequestURI();
-            MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
+            MediaServer mediaInfo = getMediaInfoByUri(requestURI);
 
             String uri = null;
             if (mediaInfo != null) {
@@ -121,7 +121,7 @@
         @Override
         protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
             String requestURI = servletRequest.getRequestURI();
-            MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
+            MediaServer mediaInfo = getMediaInfoByUri(requestURI);
             HttpHost host;
             if (mediaInfo != null) {
                 host = new HttpHost(mediaInfo.getIp(), mediaInfo.getHttpPort());
@@ -135,7 +135,7 @@
         /**
          * 鏍规嵁uri鑾峰彇娴佸獟浣撲俊鎭�
          */
-        MediaServerItem getMediaInfoByUri(String uri){
+        MediaServer getMediaInfoByUri(String uri){
             String[] split = uri.split("/");
             String mediaServerId = split[2];
             if ("default".equalsIgnoreCase(mediaServerId)) {
@@ -151,7 +151,7 @@
         @Override
         protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
             String requestURI = servletRequest.getRequestURI();
-            MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
+            MediaServer mediaInfo = getMediaInfoByUri(requestURI);
             String url = super.rewriteUrlFromRequest(servletRequest);
             if (mediaInfo == null) {
                 logger.error("[ZLM鏈嶅姟璁块棶浠g悊]锛岄敊璇細澶勭悊url淇℃伅鏃舵湭鎵惧埌娴佸獟浣撲俊鎭�=>{}", requestURI);
@@ -181,7 +181,7 @@
         @Override
         protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
             String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
-            MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
+            MediaServer mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
             if (mediaInfo == null) {
                 return null;
             }
@@ -238,7 +238,7 @@
         @Override
         protected String getTargetUri(HttpServletRequest servletRequest) {
             String requestURI = servletRequest.getRequestURI();
-            MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
+            MediaServer mediaInfo = getMediaInfoByUri(requestURI);
 
             String uri = null;
             if (mediaInfo != null) {
@@ -256,7 +256,7 @@
         @Override
         protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
             String requestURI = servletRequest.getRequestURI();
-            MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
+            MediaServer mediaInfo = getMediaInfoByUri(requestURI);
             HttpHost host;
             if (mediaInfo != null) {
                 host = new HttpHost(mediaInfo.getIp(), mediaInfo.getRecordAssistPort());
@@ -270,7 +270,7 @@
         /**
          * 鏍规嵁uri鑾峰彇娴佸獟浣撲俊鎭�
          */
-        MediaServerItem getMediaInfoByUri(String uri){
+        MediaServer getMediaInfoByUri(String uri){
             String[] split = uri.split("/");
             String mediaServerId = split[2];
             if ("default".equalsIgnoreCase(mediaServerId)) {
@@ -287,7 +287,7 @@
         @Override
         protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
             String requestURI = servletRequest.getRequestURI();
-            MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
+            MediaServer mediaInfo = getMediaInfoByUri(requestURI);
             String url = super.rewriteUrlFromRequest(servletRequest);
             if (mediaInfo == null) {
                 logger.error("[褰曞儚鏈嶅姟璁块棶浠g悊]锛岄敊璇細澶勭悊url淇℃伅鏃舵湭鎵惧埌娴佸獟浣撲俊鎭�=>{}", requestURI);
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/WVPTimerTask.java b/src/main/java/com/genersoft/iot/vmp/conf/WVPTimerTask.java
index 77d83ee..c586255 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/WVPTimerTask.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/WVPTimerTask.java
@@ -1,7 +1,6 @@
 package com.genersoft.iot.vmp.conf;
 
 import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -13,9 +12,6 @@
 
     @Autowired
     private IRedisCatchStorage redisCatchStorage;
-
-    @Autowired
-    private IMediaServerService mediaServerService;
 
     @Value("${server.port}")
     private int serverPort;
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
index ad959d6..b035fcb 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
@@ -117,7 +117,7 @@
                 .authorizeRequests()
                 .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                 .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll()
-                .antMatchers("/api/user/login", "/index/hook/**", "/swagger-ui/**", "/doc.html").permitAll()
+                .antMatchers("/api/user/login", "/index/hook/**","/index/hook/abl/**", "/swagger-ui/**", "/doc.html").permitAll()
                 .anyRequest().authenticated()
                 // 寮傚父澶勭悊鍣�
                 .and()
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java
index 814d984..2b5e16b 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java
@@ -1,7 +1,7 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
 
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
 import gov.nist.javax.sip.message.SIPResponse;
 
@@ -15,7 +15,7 @@
     public AudioBroadcastCatch(
             String deviceId,
             String channelId,
-            MediaServerItem mediaServerItem,
+            MediaServer mediaServerItem,
             String app,
             String stream,
             AudioBroadcastEvent event,
@@ -48,7 +48,7 @@
     /**
      * 娴佸獟浣撲俊鎭�
      */
-    private MediaServerItem mediaServerItem;
+    private MediaServer mediaServerItem;
 
     /**
      * 鍏宠仈鐨勬祦APP
@@ -109,11 +109,11 @@
         return sipTransactionInfo;
     }
 
-    public MediaServerItem getMediaServerItem() {
+    public MediaServer getMediaServerItem() {
         return mediaServerItem;
     }
 
-    public void setMediaServerItem(MediaServerItem mediaServerItem) {
+    public void setMediaServerItem(MediaServer mediaServerItem) {
         this.mediaServerItem = mediaServerItem;
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamInfo.java
index 134930b..e1925fa 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamInfo.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamInfo.java
@@ -1,11 +1,11 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
 import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 
 public class InviteStreamInfo {
 
-    public InviteStreamInfo(MediaServerItem mediaServerItem, JSONObject response, String callId, String app, String stream) {
+    public InviteStreamInfo(MediaServer mediaServerItem, JSONObject response, String callId, String app, String stream) {
         this.mediaServerItem = mediaServerItem;
         this.response = response;
         this.callId = callId;
@@ -13,17 +13,17 @@
         this.stream = stream;
     }
 
-    private MediaServerItem mediaServerItem;
+    private MediaServer mediaServerItem;
     private JSONObject response;
     private String callId;
     private String app;
     private String stream;
 
-    public MediaServerItem getMediaServerItem() {
+    public MediaServer getMediaServerItem() {
         return mediaServerItem;
     }
 
-    public void setMediaServerItem(MediaServerItem mediaServerItem) {
+    public void setMediaServerItem(MediaServer mediaServerItem) {
         this.mediaServerItem = mediaServerItem;
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
index c0b66fe..299d59a 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
@@ -1,17 +1,16 @@
 package com.genersoft.iot.vmp.gb28181.event;
 
 import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent;
 import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent;
 import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent;
 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
 import com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition.MobilePositionEvent;
-import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent;
-import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent;
+import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOfflineEvent;
+import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOnlineEvent;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Component;
-
-import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent;
 
 import javax.sip.TimeoutEvent;
 import java.util.ArrayList;
@@ -40,14 +39,14 @@
 		applicationEventPublisher.publishEvent(alarmEvent);
 	}
 
-	public void zlmOfflineEventPublish(String mediaServerId){
-		ZLMOfflineEvent outEvent = new ZLMOfflineEvent(this);
+	public void mediaServerOfflineEventPublish(String mediaServerId){
+		MediaServerOfflineEvent outEvent = new MediaServerOfflineEvent(this);
 		outEvent.setMediaServerId(mediaServerId);
 		applicationEventPublisher.publishEvent(outEvent);
 	}
 
-	public void zlmOnlineEventPublish(String mediaServerId) {
-		ZLMOnlineEvent outEvent = new ZLMOnlineEvent(this);
+	public void mediaServerOnlineEventPublish(String mediaServerId) {
+		MediaServerOnlineEvent outEvent = new MediaServerOnlineEvent(this);
 		outEvent.setMediaServerId(mediaServerId);
 		applicationEventPublisher.publishEvent(outEvent);
 	}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java
index 343d2a6..24eadba 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java
@@ -3,6 +3,8 @@
 import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch;
 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -18,11 +20,14 @@
 @Component
 public class AudioBroadcastManager {
 
+    private final static Logger logger = LoggerFactory.getLogger(AudioBroadcastManager.class);
+
     @Autowired
     private SipConfig config;
 
     public static Map<String, AudioBroadcastCatch> data = new ConcurrentHashMap<>();
 
+
     public void update(AudioBroadcastCatch audioBroadcastCatch) {
         if (SipUtils.isFrontEnd(audioBroadcastCatch.getDeviceId())) {
             audioBroadcastCatch.setChannelId(audioBroadcastCatch.getDeviceId());
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
index 5ca95a0..b61a623 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
@@ -1,16 +1,14 @@
 package com.genersoft.iot.vmp.gb28181.task;
 
-import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
 import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
-import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.IDeviceService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IPlatformService;
 import com.genersoft.iot.vmp.service.impl.PlatformServiceImpl;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -52,9 +50,6 @@
 
     @Autowired
     private IDeviceService deviceService;
-
-    @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
 
     @Autowired
     private IMediaServerService mediaServerService;
@@ -105,17 +100,12 @@
         List<SendRtpItem> sendRtpItems = redisCatchStorage.queryAllSendRTPServer();
         if (sendRtpItems.size() > 0) {
             for (SendRtpItem sendRtpItem : sendRtpItems) {
-                MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+                MediaServer mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
                 redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(),sendRtpItem.getChannelId(), sendRtpItem.getCallId(),sendRtpItem.getStream());
                 if (mediaServerItem != null) {
                     ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
-                    Map<String, Object> param = new HashMap<>();
-                    param.put("vhost","__defaultVhost__");
-                    param.put("app",sendRtpItem.getApp());
-                    param.put("stream",sendRtpItem.getStream());
-                    param.put("ssrc",sendRtpItem.getSsrc());
-                    JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param);
-                    if (jsonObject != null && jsonObject.getInteger("code") == 0) {
+                    boolean stopResult = mediaServerService.stopSendRtp(mediaServerItem, sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getSsrc());
+                    if (stopResult) {
                         ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId());
                         if (platform != null) {
                             try {
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 66589a8..fcafbf7 100755
--- 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
@@ -7,8 +7,8 @@
 import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 import gov.nist.javax.sip.message.SIPRequest;
 
@@ -100,7 +100,7 @@
 	 * @param device  瑙嗛璁惧
 	 * @param channel  棰勮閫氶亾
 	 */
-	void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
+	void playStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel, HookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
 
 	/**
 	 * 璇锋眰鍥炴斁瑙嗛娴�
@@ -110,7 +110,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,ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
+	void playbackStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime, HookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
 
 	/**
 	 * 璇锋眰鍘嗗彶濯掍綋涓嬭浇
@@ -121,9 +121,9 @@
 	 * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 * @param downloadSpeed 涓嬭浇鍊嶉�熷弬鏁�
 	 */ 
-	void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
-						   String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent,
-						   SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
+	void downloadStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
+                           String startTime, String endTime, int downloadSpeed, HookSubscribe.Event hookEvent,
+                           SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
 
 
 	/**
@@ -131,7 +131,7 @@
 	 */
 	void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
 
-	void talkStreamCmd(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
+	void talkStreamCmd(MediaServer mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, HookSubscribe.Event event, HookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
 
 
 	void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException;
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
index a412a6c..bc999f0 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
@@ -3,8 +3,8 @@
 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
 import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 
@@ -154,8 +154,8 @@
 
     void streamByeCmd(ParentPlatform platform, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
 
-    void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem,
-                            SSRCInfo ssrcInfo, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent,
+    void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServer mediaServerItem,
+                            SSRCInfo ssrcInfo, HookSubscribe.Event event, SipSubscribe.Event okEvent,
                             SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException;
 
     void broadcastResultCmd(ParentPlatform platform, DeviceChannel deviceChannel, String sn, boolean result, SipSubscribe.Event errorEvent,  SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
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 3a5f812..dab039f 100755
--- 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
@@ -7,10 +7,6 @@
 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
 import com.genersoft.iot.vmp.gb28181.SipLayer;
 import com.genersoft.iot.vmp.gb28181.bean.*;
-import com.genersoft.iot.vmp.gb28181.bean.Device;
-import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
-import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
-import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
@@ -18,14 +14,12 @@
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
 import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
+import com.genersoft.iot.vmp.media.event.hook.Hook;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.event.hook.HookType;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamPush;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import gov.nist.javax.sip.message.SIPRequest;
@@ -44,7 +38,6 @@
 import javax.sip.header.CallIdHeader;
 import javax.sip.message.Request;
 import java.text.ParseException;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -77,7 +70,7 @@
     private UserSetting userSetting;
 
     @Autowired
-    private ZlmHttpHookSubscribe subscribe;
+    private HookSubscribe subscribe;
 
     @Autowired
     private IMediaServerService mediaServerService;
@@ -275,8 +268,8 @@
      * @param errorEvent sip閿欒璁㈤槄
      */
     @Override
-    public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel,
-                              ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
+    public void playStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel,
+                              HookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
         String stream = ssrcInfo.getStream();
 
         if (device == null) {
@@ -284,11 +277,11 @@
         }
 
         logger.info("{} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
-        HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
-        subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
+        Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, "rtp", stream, mediaServerItem.getId());
+        subscribe.addSubscribe(rtpHook, (hookData) -> {
             if (event != null) {
-                event.response(mediaServerItemInUse, hookParam);
-                subscribe.removeSubscribe(hookSubscribe);
+                event.response(hookData);
+                subscribe.removeSubscribe(rtpHook);
             }
         });
         String sdpIp;
@@ -384,8 +377,8 @@
      * @param endTime   缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
      */
     @Override
-    public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
-                                  String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent,
+    public void playbackStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
+                                  String startTime, String endTime, HookSubscribe.Event hookEvent,
                                   SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
 
 
@@ -458,13 +451,13 @@
         //ssrc
         content.append("y=" + ssrcInfo.getSsrc() + "\r\n");
 
-        HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
+        Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, "rtp", ssrcInfo.getStream(), mediaServerItem.getId());
         // 娣诲姞璁㈤槄
-        subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
+        subscribe.addSubscribe(rtpHook, (hookData) -> {
             if (hookEvent != null) {
-                hookEvent.response(mediaServerItemInUse, hookParam);
+                hookEvent.response(hookData);
             }
-            subscribe.removeSubscribe(hookSubscribe);
+            subscribe.removeSubscribe(rtpHook);
         });
         Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
 
@@ -486,10 +479,10 @@
      * @param downloadSpeed 涓嬭浇鍊嶉�熷弬鏁�
      */
     @Override
-    public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
+    public void downloadStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
                                   String startTime, String endTime, int downloadSpeed,
-                                  ZlmHttpHookSubscribe.Event hookEvent,
-                                  SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
+                                  HookSubscribe.Event hookEvent,
+                                  SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
 
         logger.info("{} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
         String sdpIp;
@@ -559,19 +552,18 @@
 
         content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
         logger.debug("姝ゆ椂璇锋眰涓嬭浇淇′护鐨剆src===>{}",ssrcInfo.getSsrc());
-        HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
+        Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, "rtp", ssrcInfo.getStream(), mediaServerItem.getId());
         // 娣诲姞璁㈤槄
         CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
         String callId= newCallIdHeader.getCallId();
-        subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
+        subscribe.addSubscribe(rtpHook, (hookData) -> {
             logger.debug("sipc 娣诲姞璁㈤槄===callId {}",callId);
-            hookEvent.response(mediaServerItemInUse, hookParam);
-            subscribe.removeSubscribe(hookSubscribe);
-            hookSubscribe.getContent().put("regist", false);
-            hookSubscribe.getContent().put("schema", "rtsp");
+            hookEvent.response(hookData);
+            subscribe.removeSubscribe(rtpHook);
             // 娣诲姞娴佹敞閿�鐨勮闃咃紝娉ㄩ攢浜嗗悗鍚戣澶囧彂閫乥ye
-            subscribe.addSubscribe(hookSubscribe,
-                    (mediaServerItemForEnd, hookParam1) -> {
+            Hook departureHook = Hook.getInstance(HookType.on_media_departure, "rtp", ssrcInfo.getStream(), mediaServerItem.getId());
+            subscribe.addSubscribe(departureHook,
+                    (departureHookData) -> {
                         logger.info("[褰曞儚]涓嬭浇缁撴潫锛� 鍙戦�丅YE");
                         try {
                             streamByeCmd(device, channelId, ssrcInfo.getStream(), callId);
@@ -595,7 +587,7 @@
     }
 
     @Override
-    public void talkStreamCmd(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
+    public void talkStreamCmd(MediaServer mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, HookSubscribe.Event event, HookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
 
         String stream = sendRtpItem.getStream();
 
@@ -609,20 +601,20 @@
         }
 
         logger.info("[璇煶鍠婅瘽] {} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), sendRtpItem.getPort());
-        HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
-        subscribe.addSubscribe(hookSubscribeForStreamChange, (mediaServerItemInUse, hookParam) -> {
+        Hook hook = Hook.getInstance(HookType.on_media_arrival, "rtp", stream, mediaServerItem.getId());
+        subscribe.addSubscribe(hook, (hookData) -> {
             if (event != null) {
-                event.response(mediaServerItemInUse, hookParam);
-                subscribe.removeSubscribe(hookSubscribeForStreamChange);
+                event.response(hookData);
+                subscribe.removeSubscribe(hook);
             }
         });
 
         CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
         callIdHeader.setCallId(callId);
-        HookSubscribeForStreamPush hookSubscribeForStreamPush = HookSubscribeFactory.on_publish("rtp", stream,  null, mediaServerItem.getId());
-        subscribe.addSubscribe(hookSubscribeForStreamPush, (mediaServerItemInUse, hookParam) -> {
+        Hook publishHook = Hook.getInstance(HookType.on_publish, "rtp", stream, mediaServerItem.getId());
+        subscribe.addSubscribe(publishHook, (hookData) -> {
             if (eventForPush != null) {
-                eventForPush.response(mediaServerItemInUse, hookParam);
+                eventForPush.response(hookData);
             }
         });
         //
@@ -1265,7 +1257,6 @@
      * @param startPriority 鎶ヨ璧峰绾у埆锛堝彲閫夛級
      * @param endPriority   鎶ヨ缁堟绾у埆锛堝彲閫夛級
      * @param alarmMethod   鎶ヨ鏂瑰紡鏉′欢锛堝彲閫夛級
-     * @param alarmType     鎶ヨ绫诲瀷
      * @param startTime     鎶ヨ鍙戠敓璧峰鏃堕棿锛堝彲閫夛級
      * @param endTime       鎶ヨ鍙戠敓缁堟鏃堕棿锛堝彲閫夛級
      * @return true = 鍛戒护鍙戦�佹垚鍔�
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
index 2964654..51f5c67 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -13,13 +13,12 @@
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider;
 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
+import com.genersoft.iot.vmp.media.event.hook.Hook;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.event.hook.HookType;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -76,7 +75,7 @@
     private SIPSender sipSender;
 
     @Autowired
-    private ZlmHttpHookSubscribe subscribe;
+    private HookSubscribe subscribe;
 
     @Autowired
     private UserSetting userSetting;
@@ -844,7 +843,7 @@
         }
         logger.info("[鍚戜笂绾у彂閫丅YE]锛� {}/{}", platform.getServerGBId(), sendRtpItem.getChannelId());
         String mediaServerId = sendRtpItem.getMediaServerId();
-        MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
+        MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId);
         if (mediaServerItem != null) {
             mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
             zlmServerFactory.closeRtpServer(mediaServerItem, sendRtpItem.getStream());
@@ -895,8 +894,8 @@
     }
 
     @Override
-    public void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem,
-                                   SSRCInfo ssrcInfo, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent,
+    public void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServer mediaServerItem,
+                                   SSRCInfo ssrcInfo, HookSubscribe.Event event, SipSubscribe.Event okEvent,
                                    SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException {
         String stream = ssrcInfo.getStream();
 
@@ -905,11 +904,11 @@
         }
 
         logger.info("{} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
-        HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
-        subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
+        Hook hook = Hook.getInstance(HookType.on_media_arrival, "rtp", stream, mediaServerItem.getId());
+        subscribe.addSubscribe(hook, (hookData) -> {
             if (event != null) {
-                event.response(mediaServerItemInUse, hookParam);
-                subscribe.removeSubscribe(hookSubscribe);
+                event.response(hookData);
+                subscribe.removeSubscribe(hook);
             }
         });
         String sdpIp = mediaServerItem.getSdpIp();
@@ -949,7 +948,7 @@
         sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> {
             streamSession.remove(platform.getServerGBId(), channelId, ssrcInfo.getStream());
             mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
-            subscribe.removeSubscribe(hookSubscribe);
+            subscribe.removeSubscribe(hook);
             errorEvent.response(e);
         }), e -> {
             ResponseEvent responseEvent = (ResponseEvent) e.event;
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 242e5ef..5410d67 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
@@ -3,6 +3,9 @@
 import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.conf.UserSetting;
+import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
+import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
@@ -10,10 +13,10 @@
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.IDeviceService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IPlayService;
 import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
@@ -25,12 +28,15 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import javax.sip.InvalidArgumentException;
 import javax.sip.RequestEvent;
+import javax.sip.SipException;
 import javax.sip.address.SipURI;
 import javax.sip.header.CallIdHeader;
 import javax.sip.header.FromHeader;
 import javax.sip.header.HeaderAddress;
 import javax.sip.header.ToHeader;
+import java.text.ParseException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -69,7 +75,7 @@
 	private ZLMServerFactory zlmServerFactory;
 
 	@Autowired
-	private ZlmHttpHookSubscribe hookSubscribe;
+	private HookSubscribe hookSubscribe;
 
 	@Autowired
 	private IMediaServerService mediaServerService;
@@ -104,7 +110,7 @@
 			logger.info("鏀跺埌ACK锛宺tp/{} TCP涓诲姩鏂瑰紡鍚庣画澶勭悊", sendRtpItem.getStream());
 			return;
 		}
-		MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+		MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
 		logger.info("鏀跺埌ACK锛宺tp/{}寮�濮嬪悜涓婄骇鎺ㄦ祦, 鐩爣={}:{}锛孲SRC={}, 鍗忚:{}",
 				sendRtpItem.getStream(),
 				sendRtpItem.getIp(),
@@ -115,19 +121,24 @@
 		ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(fromUserId);
 
 		if (parentPlatform != null) {
-			Map<String, Object> param = getSendRtpParam(sendRtpItem);
 			if (!userSetting.getServerId().equals(sendRtpItem.getServerId())) {
 				RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
 						sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStream(),
 						sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),
 						sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());
 				redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> {
-					playService.startSendRtpStreamHand(sendRtpItem, parentPlatform, json, param, callIdHeader);
+					playService.startSendRtpStreamFailHand(sendRtpItem, parentPlatform, callIdHeader);
 				});
 			} else {
-				JSONObject startSendRtpStreamResult = sendRtp(sendRtpItem, mediaInfo, param);
-				if (startSendRtpStreamResult != null) {
-					playService.startSendRtpStreamHand(sendRtpItem, parentPlatform, startSendRtpStreamResult, param, callIdHeader);
+				try {
+					if (sendRtpItem.isTcpActive()) {
+						mediaServerService.startSendRtpPassive(mediaInfo, parentPlatform, sendRtpItem, null);
+					} else {
+						mediaServerService.startSendRtpStream(mediaInfo, parentPlatform, sendRtpItem);
+					}
+				}catch (ControllerException e) {
+					logger.error("RTP鎺ㄦ祦澶辫触: {}", e.getMessage());
+					playService.startSendRtpStreamFailHand(sendRtpItem, parentPlatform, callIdHeader);
 				}
 			}
 		}else {
@@ -144,56 +155,17 @@
 				logger.warn("[鏀跺埌ACK]锛氭潵鑷獅}锛岀洰鏍囦负({})鐨勬帹娴佷俊鎭负鎵惧埌娴佷綋鏈嶅姟[{}]淇℃伅",fromUserId, toUserId, sendRtpItem.getMediaServerId());
 				return;
 			}
-			Map<String, Object> param = getSendRtpParam(sendRtpItem);
-			JSONObject startSendRtpStreamResult = sendRtp(sendRtpItem, mediaInfo, param);
-			if (startSendRtpStreamResult != null) {
-				playService.startSendRtpStreamHand(sendRtpItem, device, startSendRtpStreamResult, param, callIdHeader);
+			try {
+				if (sendRtpItem.isTcpActive()) {
+					mediaServerService.startSendRtpPassive(mediaInfo, null, sendRtpItem, null);
+				} else {
+					mediaServerService.startSendRtpStream(mediaInfo, null, sendRtpItem);
+				}
+			}catch (ControllerException e) {
+				logger.error("RTP鎺ㄦ祦澶辫触: {}", e.getMessage());
+				playService.startSendRtpStreamFailHand(sendRtpItem, null, callIdHeader);
 			}
 		}
-	}
-
-	private Map<String, Object> getSendRtpParam(SendRtpItem sendRtpItem) {
-		String isUdp = sendRtpItem.isTcp() ? "0" : "1";
-		Map<String, Object> param = new HashMap<>(12);
-		param.put("vhost","__defaultVhost__");
-		param.put("app",sendRtpItem.getApp());
-		param.put("stream",sendRtpItem.getStream());
-		param.put("ssrc", sendRtpItem.getSsrc());
-		param.put("dst_url",sendRtpItem.getIp());
-		param.put("dst_port", sendRtpItem.getPort());
-		param.put("src_port", sendRtpItem.getLocalPort());
-		param.put("pt", sendRtpItem.getPt());
-		param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
-		param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
-		param.put("is_udp", isUdp);
-		if (!sendRtpItem.isTcp()) {
-			// udp妯″紡涓嬪紑鍚痳tcp淇濇椿
-			param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
-		}
-		return param;
-	}
-
-	private JSONObject sendRtp(SendRtpItem sendRtpItem, MediaServerItem mediaInfo, Map<String, Object> param){
-		JSONObject startSendRtpStreamResult = null;
-		if (sendRtpItem.getLocalPort() != 0) {
-			if (sendRtpItem.isTcpActive()) {
-				startSendRtpStreamResult = zlmServerFactory.startSendRtpPassive(mediaInfo, param);
-			}else {
-				param.put("dst_url", sendRtpItem.getIp());
-				param.put("dst_port", sendRtpItem.getPort());
-				startSendRtpStreamResult = zlmServerFactory.startSendRtpStream(mediaInfo, param);
-			}
-		}else {
-			if (sendRtpItem.isTcpActive()) {
-				startSendRtpStreamResult = zlmServerFactory.startSendRtpPassive(mediaInfo, param);
-			}else {
-				param.put("dst_url", sendRtpItem.getIp());
-				param.put("dst_port", sendRtpItem.getPort());
-				startSendRtpStreamResult = zlmServerFactory.startSendRtpStream(mediaInfo, param);
-			}
-		}
-		return startSendRtpStreamResult;
-
 	}
 
 }
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 ff7427b..b2d14a0 100755
--- 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
@@ -13,8 +13,9 @@
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.genersoft.iot.vmp.service.*;
 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
@@ -145,7 +146,7 @@
 						redisGbPlayMsgListener.sendMsgForStopSendRtpStream(sendRtpItem.getServerId(), streamMsg);
 					}
 				}else {
-					MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+					MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
 					redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(),
 							callIdHeader.getCallId(), null);
 					zlmServerFactory.stopSendRtpStream(mediaInfo, param);
@@ -165,7 +166,7 @@
 					}
 				}
 			}else {
-				MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+				MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
 				redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(),
 						callIdHeader.getCallId(), null);
 				zlmServerFactory.stopSendRtpStream(mediaInfo, param);
@@ -173,7 +174,7 @@
 					mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc());
 				}
 			}
-			MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+			MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
 			if (mediaInfo != null) {
 				AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
 				if (audioBroadcastCatch != null && audioBroadcastCatch.getSipTransactionInfo().getCallId().equals(callIdHeader.getCallId())) {
@@ -245,7 +246,7 @@
 				}
 			}
 			// 閲婃斁ssrc
-			MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
+			MediaServer mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
 			if (mediaServerItem != null) {
 				mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc());
 			}
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 96b8b11..b4d183e 100755
--- 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
@@ -18,12 +18,19 @@
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.event.hook.Hook;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.event.hook.HookType;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.*;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
-import com.genersoft.iot.vmp.service.*;
+import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
+import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
+import com.genersoft.iot.vmp.service.IInviteStreamService;
+import com.genersoft.iot.vmp.service.IPlayService;
+import com.genersoft.iot.vmp.service.IStreamProxyService;
+import com.genersoft.iot.vmp.service.IStreamPushService;
 import com.genersoft.iot.vmp.service.bean.ErrorCallback;
 import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
@@ -113,7 +120,7 @@
     private IMediaServerService mediaServerService;
 
     @Autowired
-    private ZlmHttpHookSubscribe zlmHttpHookSubscribe;
+    private HookSubscribe hookSubscribe;
 
     @Autowired
     private SIPProcessorObserver sipProcessorObserver;
@@ -192,7 +199,7 @@
                 GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
                 PlatformCatalog catalog = storager.getCatalog(requesterId, channelId);
 
-                MediaServerItem mediaServerItem = null;
+                MediaServer mediaServerItem = null;
                 StreamPushItem streamPushItem = null;
                 StreamProxyItem proxyByAppAndStream = null;
                 // 涓嶆槸閫氶亾鍙兘鏄洿鎾祦
@@ -398,7 +405,7 @@
                     Long finalStopTime = stopTime;
                     ErrorCallback<Object> hookEvent = (code, msg, data) -> {
                         StreamInfo streamInfo = (StreamInfo)data;
-                        MediaServerItem mediaServerItemInUSe = mediaServerService.getOne(streamInfo.getMediaServerId());
+                        MediaServer mediaServerItemInUSe = mediaServerService.getOne(streamInfo.getMediaServerId());
                         logger.info("[涓婄骇Invite]涓嬬骇宸茬粡寮�濮嬫帹娴併�� 鍥炲200OK(SDP)锛� {}/{}", streamInfo.getApp(), streamInfo.getStream());
                         //     * 0 绛夊緟璁惧鎺ㄦ祦涓婃潵
                         //     * 1 涓嬬骇宸茬粡鎺ㄦ祦锛岀瓑寰呬笂绾у钩鍙板洖澶峚ck
@@ -455,7 +462,7 @@
                             responseSdpAck(request, content.toString(), platform);
                             // tcp涓诲姩妯″紡锛屽洖澶峴dp鍚庡紑鍚洃鍚�
                             if (sendRtpItem.isTcpActive()) {
-                                MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+                                MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
                                 Map<String, Object> param = new HashMap<>(12);
                                 param.put("vhost","__defaultVhost__");
                                 param.put("app",sendRtpItem.getApp());
@@ -485,12 +492,11 @@
                         }
                     };
                     ErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> {
+                        logger.info("[涓婄骇Invite] {}, 澶辫触, 骞冲彴锛歿}锛� 閫氶亾锛歿}, code锛� {}锛� msg锛泏}", sessionName, username, channelId, statusCode, msg);
                         // 鏈煡閿欒銆傜洿鎺ヨ浆鍙戣澶囩偣鎾殑閿欒
                         try {
-                            if (statusCode > 0) {
-                                Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
-                                sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
-                            }
+                            Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
+                            sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
                         } catch (ParseException | SipException e) {
                             logger.error("鏈鐞嗙殑寮傚父 ", e);
                         }
@@ -501,7 +507,7 @@
                         String startTimeStr = DateUtil.urlFormatter.format(start);
                         String endTimeStr = DateUtil.urlFormatter.format(end);
                         String stream = device.getDeviceId() + "_" + channelId + "_" + startTimeStr + "_" + endTimeStr;
-                        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, stream, null, device.isSsrcCheck(), true, 0,false, false, device.getStreamModeForParam());
+                        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, stream, null, device.isSsrcCheck(), true, 0,false,!channel.isHasAudio(), false, device.getStreamModeForParam());
                         sendRtpItem.setStream(stream);
                         // 鍐欏叆redis锛� 瓒呮椂鏃跺洖澶�
                         redisCatchStorage.updateSendRTPSever(sendRtpItem);
@@ -531,7 +537,7 @@
                         }
 
                         sendRtpItem.setPlayType(InviteStreamType.DOWNLOAD);
-                        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, false, device.getStreamModeForParam());
+                        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false,!channel.isHasAudio(), false, device.getStreamModeForParam());
                         sendRtpItem.setStream(ssrcInfo.getStream());
                         // 鍐欏叆redis锛� 瓒呮椂鏃跺洖澶�
                         redisCatchStorage.updateSendRTPSever(sendRtpItem);
@@ -581,12 +587,11 @@
                     if ("push".equals(gbStream.getStreamType())) {
                         if (streamPushItem != null) {
                             // 浠巖edis鏌ヨ鏄惁姝e湪鎺ユ敹杩欎釜鎺ㄦ祦
-                            OnStreamChangedHookParam pushListItem = redisCatchStorage.getPushListItem(gbStream.getApp(), gbStream.getStream());
+                            StreamPushItem pushListItem = redisCatchStorage.getPushListItem(gbStream.getApp(), gbStream.getStream());
                             if (pushListItem != null) {
-                                StreamPushItem transform = streamPushService.transform(pushListItem);
-                                transform.setSelf(userSetting.getServerId().equals(pushListItem.getSeverId()));
+                                pushListItem.setSelf(userSetting.getServerId().equals(pushListItem.getServerId()));
                                 // 鎺ㄦ祦鐘舵��
-                                pushStream(evt, request, gbStream, transform, platform, callIdHeader, mediaServerItem, port, tcpActive,
+                                pushStream(evt, request, gbStream, pushListItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
                                         mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
                             }else {
                                 // 鏈帹娴� 鎷夎捣
@@ -633,10 +638,10 @@
      * 瀹夋帓鎺ㄦ祦
      */
     private void pushProxyStream(RequestEvent evt, SIPRequest request, GbStream gbStream, ParentPlatform platform,
-                            CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
+                            CallIdHeader callIdHeader, MediaServer mediaServerItem,
                             int port, Boolean tcpActive, boolean mediaTransmissionTCP,
                             String channelId, String addressStr, String ssrc, String requesterId) {
-            Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
+            Boolean streamReady = mediaServerService.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
             if (streamReady != null && streamReady) {
                 // 鑷钩鍙板唴瀹�
                 SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
@@ -671,12 +676,12 @@
     }
 
     private void pushStream(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
-                            CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
+                            CallIdHeader callIdHeader, MediaServer mediaServerItem,
                             int port, Boolean tcpActive, boolean mediaTransmissionTCP,
                             String channelId, String addressStr, String ssrc, String requesterId) {
         // 鎺ㄦ祦
         if (streamPushItem.isSelf()) {
-            Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
+            Boolean streamReady = mediaServerService.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
             if (streamReady != null && streamReady) {
                 // 鑷钩鍙板唴瀹�
                 SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
@@ -723,24 +728,23 @@
      * 閫氱煡娴佷笂绾�
      */
     private void notifyStreamOnline(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
-                                    CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
+                                    CallIdHeader callIdHeader, MediaServer mediaServerItem,
                                     int port, Boolean tcpActive, boolean mediaTransmissionTCP,
                                     String channelId, String addressStr, String ssrc, String requesterId) {
         if ("proxy".equals(gbStream.getStreamType())) {
             // TODO 鎺у埗鍚敤浠ヤ娇璁惧涓婄嚎
             logger.info("[ app={}, stream={} ]閫氶亾鏈帹娴侊紝鍚敤娴佸悗寮�濮嬫帹娴�", gbStream.getApp(), gbStream.getStream());
             // 鐩戝惉娴佷笂绾�
-            HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(gbStream.getApp(), gbStream.getStream(), true, "rtsp", mediaServerItem.getId());
-            zlmHttpHookSubscribe.addSubscribe(hookSubscribe, (mediaServerItemInUSe, hookParam) -> {
-                OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam)hookParam;
-                logger.info("[涓婄骇鐐规挱]鎷夋祦浠g悊宸茬粡灏辩华锛� {}/{}", streamChangedHookParam.getApp(), streamChangedHookParam.getStream());
+            Hook hook = Hook.getInstance(HookType.on_media_arrival, gbStream.getApp(), gbStream.getStream(), mediaServerItem.getId());
+            this.hookSubscribe.addSubscribe(hook, (hookData) -> {
+                logger.info("[涓婄骇鐐规挱]鎷夋祦浠g悊宸茬粡灏辩华锛� {}/{}", hookData.getApp(), hookData.getStream());
                 dynamicTask.stop(callIdHeader.getCallId());
                 pushProxyStream(evt, request, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive,
                         mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
             });
             dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
                 logger.info("[ app={}, stream={} ] 绛夊緟鎷夋祦浠g悊娴佽秴鏃�", gbStream.getApp(), gbStream.getStream());
-                zlmHttpHookSubscribe.removeSubscribe(hookSubscribe);
+                this.hookSubscribe.removeSubscribe(hook);
             }, userSetting.getPlatformPlayTimeout());
             boolean start = streamProxyService.start(gbStream.getApp(), gbStream.getStream());
             if (!start) {
@@ -749,7 +753,7 @@
                 } catch (SipException | InvalidArgumentException | ParseException e) {
                     logger.error("[鍛戒护鍙戦�佸け璐 invite 閫氶亾鏈帹娴�: {}", e.getMessage());
                 }
-                zlmHttpHookSubscribe.removeSubscribe(hookSubscribe);
+                this.hookSubscribe.removeSubscribe(hook);
                 dynamicTask.stop(callIdHeader.getCallId());
             }
         } else if ("push".equals(gbStream.getStreamType())) {
@@ -846,7 +850,7 @@
      * 鏉ヨ嚜鍏朵粬wvp鐨勬帹娴�
      */
     private void otherWvpPushStream(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
-                                    CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
+                                    CallIdHeader callIdHeader, MediaServer mediaServerItem,
                                     int port, Boolean tcpActive, boolean mediaTransmissionTCP,
                                     String channelId, String addressStr, String ssrc, String requesterId) {
         logger.info("[绾ц仈鐐规挱]鐩存挱娴佹潵鑷叾浠栧钩鍙帮紝鍙戦�乺edis娑堟伅");
@@ -909,7 +913,7 @@
                 });
     }
 
-    public SIPResponse sendStreamAck(MediaServerItem mediaServerItem, SIPRequest request, SendRtpItem sendRtpItem, ParentPlatform platform, RequestEvent evt) {
+    public SIPResponse sendStreamAck(MediaServer mediaServerItem, SIPRequest request, SendRtpItem sendRtpItem, ParentPlatform platform, RequestEvent evt) {
 
         String sdpIp = mediaServerItem.getSdpIp();
         if (!ObjectUtils.isEmpty(platform.getSendStreamIp())) {
@@ -1055,7 +1059,7 @@
                 logger.info("璁惧{}璇锋眰璇煶娴侊紝鍦板潃锛歿}:{}锛宻src锛歿}, {}", requesterId, addressStr, port, gb28181Sdp.getSsrc(),
                         mediaTransmissionTCP ? (tcpActive ? "TCP涓诲姩" : "TCP琚姩") : "UDP");
 
-                MediaServerItem mediaServerItem = broadcastCatch.getMediaServerItem();
+                MediaServer mediaServerItem = broadcastCatch.getMediaServerItem();
                 if (mediaServerItem == null) {
                     logger.warn("鏈壘鍒拌闊冲枈璇濅娇鐢ㄧ殑zlm");
                     try {
@@ -1104,7 +1108,7 @@
 
                 redisCatchStorage.updateSendRTPSever(sendRtpItem);
 
-                Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream());
+                Boolean streamReady = mediaServerService.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream());
                 if (streamReady) {
                     sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, gb28181Sdp.getSsrc());
                 } else {
@@ -1132,7 +1136,7 @@
         }
     }
 
-    SIPResponse sendOk(Device device, SendRtpItem sendRtpItem, SessionDescription sdp, SIPRequest request, MediaServerItem mediaServerItem, boolean mediaTransmissionTCP, String ssrc) {
+    SIPResponse sendOk(Device device, SendRtpItem sendRtpItem, SessionDescription sdp, SIPRequest request, MediaServer mediaServerItem, boolean mediaTransmissionTCP, String ssrc) {
         SIPResponse sipResponse = null;
         try {
             sendRtpItem.setStatus(2);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
index 0c23ace..34d7077 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
@@ -37,7 +37,7 @@
 
     private final String method = "MESSAGE";
 
-    private static Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
+    private static final Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
 
     @Autowired
     private SIPProcessorObserver sipProcessorObserver;
@@ -100,9 +100,9 @@
                     deviceNotFoundEvent.setCallId(callIdHeader.getCallId());
                     SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent);
                     sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult);
-                };
+                }
             }else {
-                Element rootElement = null;
+                Element rootElement;
                 try {
                     rootElement = getRootElement(evt);
                     if (rootElement == null) {
@@ -110,23 +110,23 @@
                         responseAck(request, Response.BAD_REQUEST, "content is null");
                         return;
                     }
+                    String name = rootElement.getName();
+                    IMessageHandler messageHandler = messageHandlerMap.get(name);
+                    if (messageHandler != null) {
+                        if (device != null) {
+                            messageHandler.handForDevice(evt, device, rootElement);
+                        }else { // 鐢变簬涓婇潰宸茬粡鍒ゆ柇閮戒负null鍒欑洿鎺ヨ繑鍥烇紝鎵�浠ヨ繖閲宒evice鍜宲arentPlatform蹇呮湁涓�涓笉涓簄ull
+                            messageHandler.handForPlatform(evt, parentPlatform, rootElement);
+                        }
+                    }else {
+                        // 涓嶆敮鎸佺殑message
+                        // 涓嶅瓨鍦ㄥ垯鍥炲415
+                        responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE, "Unsupported message type, must Control/Notify/Query/Response");
+                    }
                 } catch (DocumentException e) {
                     logger.warn("瑙f瀽XML娑堟伅鍐呭寮傚父", e);
                     // 涓嶅瓨鍦ㄥ垯鍥炲404
                     responseAck(request, Response.BAD_REQUEST, e.getMessage());
-                }
-                String name = rootElement.getName();
-                IMessageHandler messageHandler = messageHandlerMap.get(name);
-                if (messageHandler != null) {
-                    if (device != null) {
-                        messageHandler.handForDevice(evt, device, rootElement);
-                    }else { // 鐢变簬涓婇潰宸茬粡鍒ゆ柇閮戒负null鍒欑洿鎺ヨ繑鍥烇紝鎵�浠ヨ繖閲宒evice鍜宲arentPlatform蹇呮湁涓�涓笉涓簄ull
-                        messageHandler.handForPlatform(evt, parentPlatform, rootElement);
-                    }
-                }else {
-                    // 涓嶆敮鎸佺殑message
-                    // 涓嶅瓨鍦ㄥ垯鍥炲415
-                    responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE, "Unsupported message type, must Control/Notify/Query/Response");
                 }
             }
         } catch (SipException e) {
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java
index a05847a..08be1f3 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java
@@ -1,7 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
 
 import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
 import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
@@ -9,10 +8,9 @@
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.IDeviceService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IPlatformService;
 import com.genersoft.iot.vmp.service.IPlayService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -121,15 +119,14 @@
                 return;
             }
 
-            MediaServerItem mediaServerForMinimumLoad = mediaServerService.getMediaServerForMinimumLoad(null);
+            MediaServer mediaServerForMinimumLoad = mediaServerService.getMediaServerForMinimumLoad(null);
             commanderForPlatform.broadcastResultCmd(platform, deviceChannel, sn, true,  eventResult->{
                 logger.info("[鍥芥爣绾ц仈] 璇煶鍠婅瘽 鍥炲澶辫触 platform锛� {}锛� 閿欒锛歿}/{}", platform.getServerGBId(), eventResult.statusCode, eventResult.msg);
             }, eventResult->{
 
                 // 娑堟伅鍙戦�佹垚鍔燂紝 鍚戜笂绾у彂閫乮nvite锛岃幏鍙栨帹娴�
                 try {
-                    platformService.broadcastInvite(platform, deviceChannel.getChannelId(), mediaServerForMinimumLoad,  (mediaServerItem, hookParam)->{
-                        OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam)hookParam;
+                    platformService.broadcastInvite(platform, deviceChannel.getChannelId(), mediaServerForMinimumLoad,  (hookData)->{
                         // 涓婄骇骞冲彴鎺ㄦ祦鎴愬姛
                         AudioBroadcastCatch broadcastCatch = audioBroadcastManager.get(device.getDeviceId(), targetId);
                         if (broadcastCatch != null ) {
@@ -137,20 +134,20 @@
                                 logger.info("[鍥芥爣绾ц仈] 璇煶鍠婅瘽 璁惧姝e湪浣跨敤涓� platform锛� {}锛� channel: {}",
                                         platform.getServerGBId(), deviceChannel.getChannelId());
                                 //  鏌ョ湅璇煶閫氶亾宸茬粡寤虹珛涓斿凡缁忓崰鐢� 鍥炲BYE
-                                platformService.stopBroadcast(platform, deviceChannel, streamChangedHookParam.getStream(),  true, mediaServerItem);
+                                platformService.stopBroadcast(platform, deviceChannel, hookData.getStream(),  true, hookData.getMediaServer());
                             }else {
                                 // 鏌ョ湅璇煶閫氶亾宸茬粡寤虹珛浣嗘槸鏈崰鐢�
-                                broadcastCatch.setApp(streamChangedHookParam.getApp());
-                                broadcastCatch.setStream(streamChangedHookParam.getStream());
-                                broadcastCatch.setMediaServerItem(mediaServerItem);
+                                broadcastCatch.setApp(hookData.getApp());
+                                broadcastCatch.setStream(hookData.getStream());
+                                broadcastCatch.setMediaServerItem(hookData.getMediaServer());
                                 audioBroadcastManager.update(broadcastCatch);
                                 // 鎺ㄦ祦鍒拌澶�
-                                SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, targetId, streamChangedHookParam.getStream(), null);
+                                SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, targetId, hookData.getStream(), null);
                                 if (sendRtpItem == null) {
-                                    logger.warn("[鍥芥爣绾ц仈] 璇煶鍠婅瘽 寮傚父锛屾湭鎵惧埌鍙戞祦淇℃伅锛� channelId: {}, stream: {}", targetId, streamChangedHookParam.getStream());
-                                    logger.info("[鍥芥爣绾ц仈] 璇煶鍠婅瘽 閲嶆柊寮�濮嬶紝channelId: {}, stream: {}", targetId, streamChangedHookParam.getStream());
+                                    logger.warn("[鍥芥爣绾ц仈] 璇煶鍠婅瘽 寮傚父锛屾湭鎵惧埌鍙戞祦淇℃伅锛� channelId: {}, stream: {}", targetId, hookData.getStream());
+                                    logger.info("[鍥芥爣绾ц仈] 璇煶鍠婅瘽 閲嶆柊寮�濮嬶紝channelId: {}, stream: {}", targetId, hookData.getStream());
                                     try {
-                                        playService.audioBroadcastCmd(device, targetId, mediaServerItem, streamChangedHookParam.getApp(), streamChangedHookParam.getStream(), 60, true, msg -> {
+                                        playService.audioBroadcastCmd(device, targetId, hookData.getMediaServer(), hookData.getApp(), hookData.getStream(), 60, true, msg -> {
                                             logger.info("[璇煶鍠婅瘽] 閫氶亾寤虹珛鎴愬姛, device: {}, channel: {}", device.getDeviceId(), targetId);
                                         });
                                     } catch (SipException | InvalidArgumentException | ParseException e) {
@@ -158,7 +155,7 @@
                                     }
                                 }else {
                                     // 鍙戞祦
-                                    JSONObject jsonObject = zlmServerFactory.startSendRtp(mediaServerItem, sendRtpItem);
+                                    JSONObject jsonObject = zlmServerFactory.startSendRtp(hookData.getMediaServer(), sendRtpItem);
                                     if (jsonObject != null && jsonObject.getInteger("code") == 0 ) {
                                         logger.info("[璇煶鍠婅瘽] 鑷姩鎺ㄦ祦鎴愬姛, device: {}, channel: {}", device.getDeviceId(), targetId);
                                     }else {
@@ -168,7 +165,7 @@
                             }
                         }else {
                             try {
-                                playService.audioBroadcastCmd(device, targetId, mediaServerItem, streamChangedHookParam.getApp(), streamChangedHookParam.getStream(), 60, true, msg -> {
+                                playService.audioBroadcastCmd(device, targetId, hookData.getMediaServer(), hookData.getApp(), hookData.getStream(), 60, true, msg -> {
                                     logger.info("[璇煶鍠婅瘽] 閫氶亾寤虹珛鎴愬姛, device: {}, channel: {}", device.getDeviceId(), targetId);
                                 });
                             } catch (SipException | InvalidArgumentException | ParseException e) {
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
index 55094f9..f8ff69c 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
@@ -13,9 +13,9 @@
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
+import com.genersoft.iot.vmp.media.event.hook.Hook;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.event.hook.HookType;
 import com.genersoft.iot.vmp.service.IInviteStreamService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
@@ -64,7 +64,7 @@
     private VideoStreamSessionManager sessionManager;
 
     @Autowired
-    private ZlmHttpHookSubscribe subscribe;
+    private HookSubscribe subscribe;
 
     @Autowired
     private IInviteStreamService inviteStreamService;
@@ -106,9 +106,8 @@
                     logger.error("[褰曞儚娴乚鎺ㄩ�佸畬姣曪紝鏀跺埌鍏虫祦閫氱煡锛� 鍙戦�丅YE澶辫触 {}", e.getMessage());
                 }
                 // 鍘婚櫎鐩戝惉娴佹敞閿�鑷姩鍋滄涓嬭浇鐨勭洃鍚�
-                HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcTransaction.getStream(), false, "rtsp", ssrcTransaction.getMediaServerId());
-                subscribe.removeSubscribe(hookSubscribe);
-
+                Hook hook = Hook.getInstance(HookType.on_media_arrival, "rtp", ssrcTransaction.getStream(), ssrcTransaction.getMediaServerId());
+                subscribe.removeSubscribe(hook);
                 // 濡傛灉绾ц仈鎾斁锛岄渶瑕佺粰涓婄骇鍙戦�佹閫氱煡 TODO 澶氫釜涓婄骇鍚屾椂瑙傜湅涓�涓笅绾� 鍙兘瀛樺湪鍋滈敊鐨勯棶棰橈紝闇�瑕佸皢鐐规挱CallId杩涜涓婁笅绾х粦瀹�
                 SendRtpItem sendRtpItem =  redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, null);
                 if (sendRtpItem != null) {
diff --git a/src/main/java/com/genersoft/iot/vmp/media/MediaServerConfig.java b/src/main/java/com/genersoft/iot/vmp/media/MediaServerConfig.java
new file mode 100755
index 0000000..fb9de3f
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/MediaServerConfig.java
@@ -0,0 +1,64 @@
+package com.genersoft.iot.vmp.media;
+
+import com.genersoft.iot.vmp.conf.MediaConfig;
+import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerChangeEvent;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 鍚姩鏄粠閰嶇疆鏂囦欢鍔犺浇鑺傜偣淇℃伅锛屼互鍙婂彂閫佷釜鑺傜偣鐘舵�佺鐞嗗幓鎺у埗鑺傜偣鐘舵��
+ */
+@Component
+@Order(value=12)
+public class MediaServerConfig implements CommandLineRunner {
+
+    private final static Logger logger = LoggerFactory.getLogger(MediaServerConfig.class);
+
+    @Autowired
+    private ApplicationEventPublisher applicationEventPublisher;
+
+    @Autowired
+    private IMediaServerService mediaServerService;
+
+    @Autowired
+    private MediaConfig mediaConfig;
+
+
+    @Override
+    public void run(String... strings) throws Exception {
+        // 娓呯悊鎵�鏈夊湪绾胯妭鐐圭殑缂撳瓨淇℃伅
+        mediaServerService.clearMediaServerForOnline();
+        MediaServer defaultMediaServer = mediaServerService.getDefaultMediaServer();
+        MediaServer mediaSerItemInConfig = mediaConfig.getMediaSerItem();
+        if (defaultMediaServer != null && mediaSerItemInConfig.getId().equals(defaultMediaServer.getId())) {
+            mediaServerService.update(mediaSerItemInConfig);
+        }else {
+            if (defaultMediaServer != null) {
+                mediaServerService.delete(defaultMediaServer.getId());
+            }
+            MediaServer mediaServerItem = mediaServerService.getOneFromDatabase(mediaSerItemInConfig.getId());
+            if (mediaServerItem == null) {
+                mediaServerService.add(mediaSerItemInConfig);
+            }else {
+                mediaServerService.update(mediaSerItemInConfig);
+            }
+        }
+        // 鍙戦�佸獟浣撹妭鐐瑰彉鍖栦簨浠�
+        mediaServerService.syncCatchFromDatabase();
+        // 鑾峰彇鎵�鏈夌殑zlm锛� 骞跺紑鍚富鍔ㄨ繛鎺�
+        List<MediaServer> all = mediaServerService.getAllFromDatabase();
+        logger.info("[濯掍綋鑺傜偣] 鍔犺浇鑺傜偣鍒楄〃锛� 鍏眥}涓妭鐐�", all.size());
+        MediaServerChangeEvent event = new MediaServerChangeEvent(this);
+        event.setMediaServerItemList(all);
+        applicationEventPublisher.publishEvent(event);
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/bean/MediaInfo.java b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaInfo.java
new file mode 100644
index 0000000..f1c3d58
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaInfo.java
@@ -0,0 +1,306 @@
+package com.genersoft.iot.vmp.media.bean;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.List;
+
+/**
+ * 瑙嗛淇℃伅
+ */
+@Schema(description = "瑙嗛淇℃伅")
+public class MediaInfo {
+    @Schema(description = "搴旂敤鍚�")
+    private String app;
+    @Schema(description = "娴両D")
+    private String stream;
+    @Schema(description = "娴佸獟浣撹妭鐐�")
+    private MediaServer mediaServer;
+    @Schema(description = "鍗忚")
+    private String schema;
+
+    @Schema(description = "瑙傜湅浜烘暟")
+    private Integer readerCount;
+    @Schema(description = "瑙嗛缂栫爜绫诲瀷")
+    private String videoCodec;
+    @Schema(description = "瑙嗛瀹藉害")
+    private Integer width;
+    @Schema(description = "瑙嗛楂樺害")
+    private Integer height;
+    @Schema(description = "闊抽缂栫爜绫诲瀷")
+    private String audioCodec;
+    @Schema(description = "闊抽閫氶亾鏁�")
+    private Integer audioChannels;
+    @Schema(description = "闊抽閲囨牱鐜�")
+    private Integer audioSampleRate;
+    @Schema(description = "闊抽閲囨牱鐜�")
+    private Long duration;
+    @Schema(description = "鍦ㄧ嚎")
+    private Boolean online;
+    @Schema(description = "unknown = 0,rtmp_push=1,rtsp_push=2,rtp_push=3,pull=4,ffmpeg_pull=5,mp4_vod=6,device_chn=7")
+    private Integer originType;
+    @Schema(description = "瀛樻椿鏃堕棿锛屽崟浣嶇")
+    private Long aliveSecond;
+    @Schema(description = "鏁版嵁浜х敓閫熷害锛屽崟浣峛yte/s")
+    private Long bytesSpeed;
+
+    public static MediaInfo getInstance(JSONObject jsonObject, MediaServer mediaServer) {
+        MediaInfo mediaInfo = new MediaInfo();
+        mediaInfo.setMediaServer(mediaServer);
+        String app = jsonObject.getString("app");
+        mediaInfo.setApp(app);
+        String stream = jsonObject.getString("stream");
+        mediaInfo.setStream(stream);
+        String schema = jsonObject.getString("schema");
+        mediaInfo.setSchema(schema);
+        Integer totalReaderCount = jsonObject.getInteger("totalReaderCount");
+        Boolean online = jsonObject.getBoolean("online");
+        Integer originType = jsonObject.getInteger("originType");
+        Long aliveSecond = jsonObject.getLong("aliveSecond");
+        Long bytesSpeed = jsonObject.getLong("bytesSpeed");
+        if (totalReaderCount != null) {
+            mediaInfo.setReaderCount(totalReaderCount);
+        }
+        if (online != null) {
+            mediaInfo.setOnline(online);
+        }
+        if (originType != null) {
+            mediaInfo.setOriginType(originType);
+        }
+        if (aliveSecond != null) {
+            mediaInfo.setAliveSecond(aliveSecond);
+        }
+        if (bytesSpeed != null) {
+            mediaInfo.setBytesSpeed(bytesSpeed);
+        }
+        JSONArray jsonArray = jsonObject.getJSONArray("tracks");
+        if (jsonArray.isEmpty()) {
+            return null;
+        }
+        for (int i = 0; i < jsonArray.size(); i++) {
+            JSONObject trackJson = jsonArray.getJSONObject(i);
+            Integer channels = trackJson.getInteger("channels");
+            Integer codecId = trackJson.getInteger("codec_id");
+            Integer codecType = trackJson.getInteger("codec_type");
+            Integer sampleRate = trackJson.getInteger("sample_rate");
+            Integer height = trackJson.getInteger("height");
+            Integer width = trackJson.getInteger("height");
+            Long duration = trackJson.getLongValue("duration");
+            if (channels != null) {
+                mediaInfo.setAudioChannels(channels);
+            }
+            if (sampleRate != null) {
+                mediaInfo.setAudioSampleRate(sampleRate);
+            }
+            if (height != null) {
+                mediaInfo.setHeight(height);
+            }
+            if (width != null) {
+                mediaInfo.setWidth(width);
+            }
+            if (duration > 0L) {
+                mediaInfo.setDuration(duration);
+            }
+            if (codecId != null) {
+                switch (codecId) {
+                    case 0:
+                        mediaInfo.setVideoCodec("H264");
+                        break;
+                    case 1:
+                        mediaInfo.setVideoCodec("H265");
+                        break;
+                    case 2:
+                        mediaInfo.setAudioCodec("AAC");
+                        break;
+                    case 3:
+                        mediaInfo.setAudioCodec("G711A");
+                        break;
+                    case 4:
+                        mediaInfo.setAudioCodec("G711U");
+                        break;
+                }
+            }
+        }
+        return mediaInfo;
+    }
+
+    public static MediaInfo getInstance(OnStreamChangedHookParam param, MediaServer mediaServer) {
+
+        MediaInfo mediaInfo = new MediaInfo();
+        mediaInfo.setApp(param.getApp());
+        mediaInfo.setStream(param.getStream());
+        mediaInfo.setSchema(param.getSchema());
+        mediaInfo.setMediaServer(mediaServer);
+        mediaInfo.setReaderCount(param.getTotalReaderCount());
+        mediaInfo.setOnline(param.isRegist());
+        mediaInfo.setOriginType(param.getOriginType());
+        mediaInfo.setAliveSecond(param.getAliveSecond());
+        mediaInfo.setBytesSpeed(param.getBytesSpeed());
+        List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
+        if (tracks == null || tracks.isEmpty()) {
+            return mediaInfo;
+        }
+        for (OnStreamChangedHookParam.MediaTrack mediaTrack : tracks) {
+            switch (mediaTrack.getCodec_id()) {
+                case 0:
+                    mediaInfo.setVideoCodec("H264");
+                    break;
+                case 1:
+                    mediaInfo.setVideoCodec("H265");
+                    break;
+                case 2:
+                    mediaInfo.setAudioCodec("AAC");
+                    break;
+                case 3:
+                    mediaInfo.setAudioCodec("G711A");
+                    break;
+                case 4:
+                    mediaInfo.setAudioCodec("G711U");
+                    break;
+            }
+            if (mediaTrack.getSample_rate() > 0) {
+                mediaInfo.setAudioSampleRate(mediaTrack.getSample_rate());
+            }
+            if (mediaTrack.getChannels() > 0) {
+                mediaInfo.setAudioChannels(mediaTrack.getChannels());
+            }
+            if (mediaTrack.getHeight() > 0) {
+                mediaInfo.setHeight(mediaTrack.getHeight());
+            }
+            if (mediaTrack.getWidth() > 0) {
+                mediaInfo.setWidth(mediaTrack.getWidth());
+            }
+        }
+        return mediaInfo;
+    }
+
+    public Integer getReaderCount() {
+        return readerCount;
+    }
+
+    public void setReaderCount(Integer readerCount) {
+        this.readerCount = readerCount;
+    }
+
+    public String getVideoCodec() {
+        return videoCodec;
+    }
+
+    public void setVideoCodec(String videoCodec) {
+        this.videoCodec = videoCodec;
+    }
+
+    public Integer getWidth() {
+        return width;
+    }
+
+    public void setWidth(Integer width) {
+        this.width = width;
+    }
+
+    public Integer getHeight() {
+        return height;
+    }
+
+    public void setHeight(Integer height) {
+        this.height = height;
+    }
+
+    public String getAudioCodec() {
+        return audioCodec;
+    }
+
+    public void setAudioCodec(String audioCodec) {
+        this.audioCodec = audioCodec;
+    }
+
+    public Integer getAudioChannels() {
+        return audioChannels;
+    }
+
+    public void setAudioChannels(Integer audioChannels) {
+        this.audioChannels = audioChannels;
+    }
+
+    public Integer getAudioSampleRate() {
+        return audioSampleRate;
+    }
+
+    public void setAudioSampleRate(Integer audioSampleRate) {
+        this.audioSampleRate = audioSampleRate;
+    }
+
+    public Long getDuration() {
+        return duration;
+    }
+
+    public void setDuration(Long duration) {
+        this.duration = duration;
+    }
+
+    public Boolean getOnline() {
+        return online;
+    }
+
+    public void setOnline(Boolean online) {
+        this.online = online;
+    }
+
+    public Integer getOriginType() {
+        return originType;
+    }
+
+    public void setOriginType(Integer originType) {
+        this.originType = originType;
+    }
+
+    public Long getAliveSecond() {
+        return aliveSecond;
+    }
+
+    public void setAliveSecond(Long aliveSecond) {
+        this.aliveSecond = aliveSecond;
+    }
+
+    public Long getBytesSpeed() {
+        return bytesSpeed;
+    }
+
+    public void setBytesSpeed(Long bytesSpeed) {
+        this.bytesSpeed = bytesSpeed;
+    }
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public MediaServer getMediaServer() {
+        return mediaServer;
+    }
+
+    public void setMediaServer(MediaServer mediaServer) {
+        this.mediaServer = mediaServer;
+    }
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public void setSchema(String schema) {
+        this.schema = schema;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java
similarity index 82%
rename from src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
rename to src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java
index cebfec3..decbd4e 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java
@@ -1,12 +1,12 @@
-package com.genersoft.iot.vmp.media.zlm.dto;
+package com.genersoft.iot.vmp.media.bean;
 
 
-import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
+import com.genersoft.iot.vmp.media.zlm.dto.ZLMServerConfig;
 import io.swagger.v3.oas.annotations.media.Schema;
 import org.springframework.util.ObjectUtils;
 
 @Schema(description = "娴佸獟浣撴湇鍔′俊鎭�")
-public class MediaServerItem{
+public class MediaServer {
 
     @Schema(description = "ID")
     private String id;
@@ -31,6 +31,18 @@
 
     @Schema(description = "RTMP绔彛")
     private int rtmpPort;
+
+    @Schema(description = "flv绔彛")
+    private int flvPort;
+
+    @Schema(description = "https-flv绔彛")
+    private int flvSSLPort;
+
+    @Schema(description = "ws-flv绔彛")
+    private int wsFlvPort;
+
+    @Schema(description = "wss-flv绔彛")
+    private int wsFlvSSLPort;
 
     @Schema(description = "RTMPS绔彛")
     private int rtmpSSlPort;
@@ -85,18 +97,24 @@
 
     @Schema(description = "褰曞儚瀛樺偍璺緞")
     private String recordPath;
+    @Schema(description = "绫诲瀷锛� zlm/abl")
+    private String type;
 
-    public MediaServerItem() {
+    public MediaServer() {
     }
 
-    public MediaServerItem(ZLMServerConfig zlmServerConfig, String sipIp) {
+    public MediaServer(ZLMServerConfig zlmServerConfig, String sipIp) {
         id = zlmServerConfig.getGeneralMediaServerId();
         ip = zlmServerConfig.getIp();
         hookIp = ObjectUtils.isEmpty(zlmServerConfig.getHookIp())? sipIp: zlmServerConfig.getHookIp();
         sdpIp = ObjectUtils.isEmpty(zlmServerConfig.getSdpIp())? zlmServerConfig.getIp(): zlmServerConfig.getSdpIp();
         streamIp = ObjectUtils.isEmpty(zlmServerConfig.getStreamIp())? zlmServerConfig.getIp(): zlmServerConfig.getStreamIp();
         httpPort = zlmServerConfig.getHttpPort();
+        flvPort = zlmServerConfig.getHttpPort();
+        wsFlvPort = zlmServerConfig.getHttpPort();
         httpSSlPort = zlmServerConfig.getHttpSSLport();
+        flvSSLPort = zlmServerConfig.getHttpSSLport();
+        wsFlvSSLPort = zlmServerConfig.getHttpSSLport();
         rtmpPort = zlmServerConfig.getRtmpPort();
         rtmpSSlPort = zlmServerConfig.getRtmpSslPort();
         rtpProxyPort = zlmServerConfig.getRtpProxyPort();
@@ -318,4 +336,44 @@
     public void setRecordPath(String recordPath) {
         this.recordPath = recordPath;
     }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public int getFlvPort() {
+        return flvPort;
+    }
+
+    public void setFlvPort(int flvPort) {
+        this.flvPort = flvPort;
+    }
+
+    public int getFlvSSLPort() {
+        return flvSSLPort;
+    }
+
+    public void setFlvSSLPort(int flvSSLPort) {
+        this.flvSSLPort = flvSSLPort;
+    }
+
+    public int getWsFlvPort() {
+        return wsFlvPort;
+    }
+
+    public void setWsFlvPort(int wsFlvPort) {
+        this.wsFlvPort = wsFlvPort;
+    }
+
+    public int getWsFlvSSLPort() {
+        return wsFlvSSLPort;
+    }
+
+    public void setWsFlvSSLPort(int wsFlvSSLPort) {
+        this.wsFlvSSLPort = wsFlvSSLPort;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/bean/RecordInfo.java b/src/main/java/com/genersoft/iot/vmp/media/bean/RecordInfo.java
new file mode 100644
index 0000000..aafc5db
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/bean/RecordInfo.java
@@ -0,0 +1,92 @@
+package com.genersoft.iot.vmp.media.bean;
+
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
+
+public class RecordInfo {
+    private String fileName;
+    private String filePath;
+    private long fileSize;
+    private String folder;
+    private String url;
+    private long startTime;
+    private double timeLen;
+
+    public static RecordInfo getInstance(OnRecordMp4HookParam hookParam) {
+        RecordInfo recordInfo = new RecordInfo();
+        recordInfo.setFileName(hookParam.getFile_name());
+        recordInfo.setUrl(hookParam.getUrl());
+        recordInfo.setFolder(hookParam.getFolder());
+        recordInfo.setFilePath(hookParam.getFile_path());
+        recordInfo.setFileSize(hookParam.getFile_size());
+        recordInfo.setStartTime(hookParam.getStart_time());
+        recordInfo.setTimeLen(hookParam.getTime_len());
+        return recordInfo;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+
+    public String getFilePath() {
+        return filePath;
+    }
+
+    public void setFilePath(String filePath) {
+        this.filePath = filePath;
+    }
+
+    public long getFileSize() {
+        return fileSize;
+    }
+
+    public void setFileSize(long fileSize) {
+        this.fileSize = fileSize;
+    }
+
+    public String getFolder() {
+        return folder;
+    }
+
+    public void setFolder(String folder) {
+        this.folder = folder;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public long getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(long startTime) {
+        this.startTime = startTime;
+    }
+
+    public double getTimeLen() {
+        return timeLen;
+    }
+
+    public void setTimeLen(double timeLen) {
+        this.timeLen = timeLen;
+    }
+
+    @Override
+    public String toString() {
+        return "RecordInfo{" +
+                "鏂囦欢鍚嶇О='" + fileName + '\'' +
+                ", 鏂囦欢璺緞='" + filePath + '\'' +
+                ", 鏂囦欢澶у皬=" + fileSize +
+                ", 寮�濮嬫椂闂�=" + startTime +
+                ", 鏃堕暱=" + timeLen +
+                '}';
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/bean/ResultForOnPublish.java b/src/main/java/com/genersoft/iot/vmp/media/bean/ResultForOnPublish.java
new file mode 100644
index 0000000..88f7387
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/bean/ResultForOnPublish.java
@@ -0,0 +1,59 @@
+package com.genersoft.iot.vmp.media.bean;
+
+public class ResultForOnPublish {
+
+    private boolean enable_audio;
+    private boolean enable_mp4;
+    private int mp4_max_second;
+    private String mp4_save_path;
+    private String stream_replace;
+    private Integer modify_stamp;
+
+    public boolean isEnable_audio() {
+        return enable_audio;
+    }
+
+    public void setEnable_audio(boolean enable_audio) {
+        this.enable_audio = enable_audio;
+    }
+
+    public boolean isEnable_mp4() {
+        return enable_mp4;
+    }
+
+    public void setEnable_mp4(boolean enable_mp4) {
+        this.enable_mp4 = enable_mp4;
+    }
+
+    public int getMp4_max_second() {
+        return mp4_max_second;
+    }
+
+    public void setMp4_max_second(int mp4_max_second) {
+        this.mp4_max_second = mp4_max_second;
+    }
+
+    public String getMp4_save_path() {
+        return mp4_save_path;
+    }
+
+    public void setMp4_save_path(String mp4_save_path) {
+        this.mp4_save_path = mp4_save_path;
+    }
+
+    public String getStream_replace() {
+        return stream_replace;
+    }
+
+    public void setStream_replace(String stream_replace) {
+        this.stream_replace = stream_replace;
+    }
+
+    public Integer getModify_stamp() {
+        return modify_stamp;
+    }
+
+    public void setModify_stamp(Integer modify_stamp) {
+        this.modify_stamp = modify_stamp;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/hook/Hook.java b/src/main/java/com/genersoft/iot/vmp/media/event/hook/Hook.java
new file mode 100755
index 0000000..a0dc7c3
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/hook/Hook.java
@@ -0,0 +1,86 @@
+package com.genersoft.iot.vmp.media.event.hook;
+
+/**
+ * zlm hook浜嬩欢鐨勫弬鏁�
+ * @author lin
+ */
+public class Hook {
+
+    private HookType hookType;
+
+    private String app;
+
+    private String stream;
+
+    private String mediaServerId;
+
+    private Long createTime;
+
+    public static Hook getInstance(HookType hookType, String app, String stream, String mediaServerId) {
+        Hook hookSubscribe = new Hook();
+        hookSubscribe.setApp(app);
+        hookSubscribe.setStream(stream);
+        hookSubscribe.setHookType(hookType);
+        hookSubscribe.setMediaServerId(mediaServerId);
+        hookSubscribe.setCreateTime(System.currentTimeMillis());
+        return hookSubscribe;
+    }
+
+    public HookType getHookType() {
+        return hookType;
+    }
+
+    public void setHookType(HookType hookType) {
+        this.hookType = hookType;
+    }
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public Long getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Long createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getMediaServerId() {
+        return mediaServerId;
+    }
+
+    public void setMediaServerId(String mediaServerId) {
+        this.mediaServerId = mediaServerId;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof Hook) {
+            Hook param = (Hook) obj;
+            return param.getHookType().equals(this.hookType)
+                    && param.getApp().equals(this.app)
+                    && param.getStream().equals(this.stream)
+                    && param.getMediaServerId().equals(this.mediaServerId);
+        }else {
+            return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return this.getHookType() + this.getApp() + this.getStream() + this.getMediaServerId();
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/hook/HookData.java b/src/main/java/com/genersoft/iot/vmp/media/event/hook/HookData.java
new file mode 100644
index 0000000..d4a82a7
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/hook/HookData.java
@@ -0,0 +1,132 @@
+package com.genersoft.iot.vmp.media.event.hook;
+
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
+import com.genersoft.iot.vmp.media.bean.RecordInfo;
+import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
+import com.genersoft.iot.vmp.media.event.media.MediaEvent;
+import com.genersoft.iot.vmp.media.event.media.MediaPublishEvent;
+import com.genersoft.iot.vmp.media.event.media.MediaRecordMp4Event;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+/**
+ * Hook杩斿洖鐨勫唴瀹�
+ */
+public class HookData {
+    /**
+     * 搴旂敤鍚�
+     */
+    private String app;
+    /**
+     * 娴両D
+     */
+    private String stream;
+    /**
+     * 娴佸獟浣撹妭鐐�
+     */
+    private MediaServer mediaServer;
+    /**
+     * 鍗忚
+     */
+    private String schema;
+
+    /**
+     * 娴佷俊鎭�
+     */
+    private MediaInfo mediaInfo;
+
+    /**
+     * 褰曞儚淇℃伅
+     */
+    private RecordInfo recordInfo;
+
+    @Schema(description = "鎺ㄦ祦鐨勯澶栧弬鏁�")
+    private String params;
+    public static HookData getInstance(MediaEvent mediaEvent) {
+        HookData hookData = new HookData();
+        if (mediaEvent instanceof MediaPublishEvent) {
+            MediaPublishEvent event = (MediaPublishEvent) mediaEvent;
+            hookData.setApp(event.getApp());
+            hookData.setStream(event.getStream());
+            hookData.setSchema(event.getSchema());
+            hookData.setMediaServer(event.getMediaServer());
+            hookData.setParams(event.getParams());
+        }else if (mediaEvent instanceof MediaArrivalEvent) {
+            MediaArrivalEvent event = (MediaArrivalEvent) mediaEvent;
+            hookData.setApp(event.getApp());
+            hookData.setStream(event.getStream());
+            hookData.setSchema(event.getSchema());
+            hookData.setMediaServer(event.getMediaServer());
+            hookData.setMediaInfo(event.getMediaInfo());
+        }else if (mediaEvent instanceof MediaRecordMp4Event) {
+            MediaRecordMp4Event event = (MediaRecordMp4Event) mediaEvent;
+            hookData.setApp(event.getApp());
+            hookData.setStream(event.getStream());
+            hookData.setSchema(event.getSchema());
+            hookData.setMediaServer(event.getMediaServer());
+            hookData.setRecordInfo(event.getRecordInfo());
+        }else {
+            hookData.setApp(mediaEvent.getApp());
+            hookData.setStream(mediaEvent.getStream());
+            hookData.setSchema(mediaEvent.getSchema());
+            hookData.setMediaServer(mediaEvent.getMediaServer());
+        }
+        return hookData;
+    }
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public MediaServer getMediaServer() {
+        return mediaServer;
+    }
+
+    public void setMediaServer(MediaServer mediaServer) {
+        this.mediaServer = mediaServer;
+    }
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public void setSchema(String schema) {
+        this.schema = schema;
+    }
+
+    public MediaInfo getMediaInfo() {
+        return mediaInfo;
+    }
+
+    public void setMediaInfo(MediaInfo mediaInfo) {
+        this.mediaInfo = mediaInfo;
+    }
+
+    public String getParams() {
+        return params;
+    }
+
+    public void setParams(String params) {
+        this.params = params;
+    }
+
+    public RecordInfo getRecordInfo() {
+        return recordInfo;
+    }
+
+    public void setRecordInfo(RecordInfo recordInfo) {
+        this.recordInfo = recordInfo;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/hook/HookSubscribe.java b/src/main/java/com/genersoft/iot/vmp/media/event/hook/HookSubscribe.java
new file mode 100755
index 0000000..907e904
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/hook/HookSubscribe.java
@@ -0,0 +1,107 @@
+package com.genersoft.iot.vmp.media.event.hook;
+
+import com.genersoft.iot.vmp.media.event.media.*;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * zlm hook浜嬩欢鐨勫弬鏁�
+ * @author lin
+ */
+@Component
+public class HookSubscribe {
+
+    /**
+     * 璁㈤槄鏁版嵁杩囨湡鏃堕棿
+     */
+    private final long subscribeExpire = 5 * 60 * 1000;
+
+    @FunctionalInterface
+    public interface Event{
+        void response(HookData data);
+    }
+
+    /**
+     * 娴佸埌鏉ョ殑澶勭悊
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaArrivalEvent event) {
+        if (event.getSchema() == null || "rtsp".equals(event.getSchema())) {
+            sendNotify(HookType.on_media_arrival, event);
+        }
+
+    }
+
+    /**
+     * 娴佺粨鏉熶簨浠�
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaDepartureEvent event) {
+        if (event.getSchema() == null || "rtsp".equals(event.getSchema())) {
+            sendNotify(HookType.on_media_departure, event);
+        }
+
+    }
+    /**
+     * 鎺ㄦ祦閴存潈浜嬩欢
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaPublishEvent event) {
+        sendNotify(HookType.on_publish, event);
+    }
+    /**
+     * 鎺ㄦ祦閴存潈浜嬩欢
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaRecordMp4Event event) {
+        sendNotify(HookType.on_record_mp4, event);
+    }
+
+    private final Map<String, Event> allSubscribes = new ConcurrentHashMap<>();
+    private final Map<String, Hook> allHook = new ConcurrentHashMap<>();
+
+    private void sendNotify(HookType hookType, MediaEvent event) {
+        Hook paramHook = Hook.getInstance(hookType, event.getApp(), event.getStream(), event.getMediaServer().getId());
+        Event hookSubscribeEvent = allSubscribes.get(paramHook.toString());
+        if (hookSubscribeEvent != null) {
+            HookData data = HookData.getInstance(event);
+            hookSubscribeEvent.response(data);
+        }
+    }
+
+    public void addSubscribe(Hook hook, HookSubscribe.Event event) {
+        if (hook.getCreateTime() == null) {
+            hook.setCreateTime(System.currentTimeMillis());
+        }
+        allSubscribes.put(hook.toString(), event);
+        allHook.put(hook.toString(), hook);
+    }
+
+    public void removeSubscribe(Hook hook) {
+        allSubscribes.remove(hook.toString());
+        allHook.remove(hook.toString());
+    }
+
+    /**
+     * 瀵硅闃呮暟鎹繘琛岃繃鏈熸竻鐞�
+     */
+    @Scheduled(fixedRate=subscribeExpire)   //姣�5鍒嗛挓鎵ц涓�娆�
+    public void execute(){
+        long expireTime = System.currentTimeMillis() - subscribeExpire;
+        for (Hook hook : allHook.values()) {
+            if (hook.getCreateTime() < expireTime) {
+                allSubscribes.remove(hook.toString());
+                allHook.remove(hook.toString());
+            }
+        }
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/hook/HookType.java b/src/main/java/com/genersoft/iot/vmp/media/event/hook/HookType.java
new file mode 100755
index 0000000..58bd656
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/hook/HookType.java
@@ -0,0 +1,15 @@
+package com.genersoft.iot.vmp.media.event.hook;
+
+/**
+ * hook绫诲瀷
+ * @author lin
+ */
+
+public enum HookType {
+
+    on_publish,
+    on_record_mp4,
+    on_media_arrival,
+    on_media_departure,
+    on_rtp_server_timeout,
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java
new file mode 100644
index 0000000..2379321
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java
@@ -0,0 +1,46 @@
+package com.genersoft.iot.vmp.media.event.media;
+
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
+
+/**
+ * 娴佸埌鏉ヤ簨浠�
+ */
+public class MediaArrivalEvent extends MediaEvent {
+    public MediaArrivalEvent(Object source) {
+        super(source);
+    }
+
+    public static MediaArrivalEvent getInstance(Object source, OnStreamChangedHookParam hookParam, MediaServer mediaServer){
+        MediaArrivalEvent mediaArrivalEvent = new MediaArrivalEvent(source);
+        mediaArrivalEvent.setMediaInfo(MediaInfo.getInstance(hookParam, mediaServer));
+        mediaArrivalEvent.setApp(hookParam.getApp());
+        mediaArrivalEvent.setStream(hookParam.getStream());
+        mediaArrivalEvent.setMediaServer(mediaServer);
+        mediaArrivalEvent.setSchema(hookParam.getSchema());
+        mediaArrivalEvent.setCallId(hookParam.getCallId());
+        return mediaArrivalEvent;
+    }
+
+    private MediaInfo mediaInfo;
+
+    private String callId;
+
+    public MediaInfo getMediaInfo() {
+        return mediaInfo;
+    }
+
+    public void setMediaInfo(MediaInfo mediaInfo) {
+        this.mediaInfo = mediaInfo;
+    }
+
+
+    public String getCallId() {
+        return callId;
+    }
+
+    public void setCallId(String callId) {
+        this.callId = callId;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaDepartureEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaDepartureEvent.java
new file mode 100644
index 0000000..edd945a
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaDepartureEvent.java
@@ -0,0 +1,22 @@
+package com.genersoft.iot.vmp.media.event.media;
+
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
+
+/**
+ * 娴佺寮�浜嬩欢
+ */
+public class MediaDepartureEvent extends MediaEvent {
+    public MediaDepartureEvent(Object source) {
+        super(source);
+    }
+
+    public static MediaDepartureEvent getInstance(Object source, OnStreamChangedHookParam hookParam, MediaServer mediaServer){
+        MediaDepartureEvent mediaDepartureEven = new MediaDepartureEvent(source);
+        mediaDepartureEven.setApp(hookParam.getApp());
+        mediaDepartureEven.setStream(hookParam.getStream());
+        mediaDepartureEven.setSchema(hookParam.getSchema());
+        mediaDepartureEven.setMediaServer(mediaServer);
+        return mediaDepartureEven;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaEvent.java
new file mode 100644
index 0000000..b6fb890
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaEvent.java
@@ -0,0 +1,56 @@
+package com.genersoft.iot.vmp.media.event.media;
+
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * 娴佸埌鏉ヤ簨浠�
+ */
+public class MediaEvent extends ApplicationEvent {
+
+    public MediaEvent(Object source) {
+        super(source);
+    }
+
+    private String app;
+
+    private String stream;
+
+    private MediaServer mediaServer;
+
+    private String schema;
+
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public MediaServer getMediaServer() {
+        return mediaServer;
+    }
+
+    public void setMediaServer(MediaServer mediaServer) {
+        this.mediaServer = mediaServer;
+    }
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public void setSchema(String schema) {
+        this.schema = schema;
+    }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaNotFoundEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaNotFoundEvent.java
new file mode 100644
index 0000000..2415566
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaNotFoundEvent.java
@@ -0,0 +1,22 @@
+package com.genersoft.iot.vmp.media.event.media;
+
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamNotFoundHookParam;
+
+/**
+ * 娴佹湭鎵惧埌
+ */
+public class MediaNotFoundEvent extends MediaEvent {
+    public MediaNotFoundEvent(Object source) {
+        super(source);
+    }
+
+    public static MediaNotFoundEvent getInstance(Object source, OnStreamNotFoundHookParam hookParam, MediaServer mediaServer){
+        MediaNotFoundEvent mediaDepartureEven = new MediaNotFoundEvent(source);
+        mediaDepartureEven.setApp(hookParam.getApp());
+        mediaDepartureEven.setStream(hookParam.getStream());
+        mediaDepartureEven.setSchema(hookParam.getSchema());
+        mediaDepartureEven.setMediaServer(mediaServer);
+        return mediaDepartureEven;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaPublishEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaPublishEvent.java
new file mode 100644
index 0000000..0d9f032
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaPublishEvent.java
@@ -0,0 +1,33 @@
+package com.genersoft.iot.vmp.media.event.media;
+
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnPublishHookParam;
+
+/**
+ * 鎺ㄦ祦閴存潈浜嬩欢
+ */
+public class MediaPublishEvent extends MediaEvent {
+    public MediaPublishEvent(Object source) {
+        super(source);
+    }
+
+    public static MediaPublishEvent getInstance(Object source, OnPublishHookParam hookParam, MediaServer mediaServer){
+        MediaPublishEvent mediaPublishEvent = new MediaPublishEvent(source);
+        mediaPublishEvent.setApp(hookParam.getApp());
+        mediaPublishEvent.setStream(hookParam.getStream());
+        mediaPublishEvent.setMediaServer(mediaServer);
+        mediaPublishEvent.setSchema(hookParam.getSchema());
+        mediaPublishEvent.setParams(hookParam.getParams());
+        return mediaPublishEvent;
+    }
+
+    private String params;
+
+    public String getParams() {
+        return params;
+    }
+
+    public void setParams(String params) {
+        this.params = params;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaRecordMp4Event.java b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaRecordMp4Event.java
new file mode 100644
index 0000000..093c3c2
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaRecordMp4Event.java
@@ -0,0 +1,35 @@
+package com.genersoft.iot.vmp.media.event.media;
+
+import com.genersoft.iot.vmp.media.bean.RecordInfo;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
+
+/**
+ * 褰曞儚鏂囦欢鐢熸垚浜嬩欢
+ */
+public class MediaRecordMp4Event extends MediaEvent {
+    public MediaRecordMp4Event(Object source) {
+        super(source);
+    }
+
+    private RecordInfo recordInfo;
+
+    public static MediaRecordMp4Event getInstance(Object source, OnRecordMp4HookParam hookParam, MediaServer mediaServer){
+        MediaRecordMp4Event mediaRecordMp4Event = new MediaRecordMp4Event(source);
+        mediaRecordMp4Event.setApp(hookParam.getApp());
+        mediaRecordMp4Event.setStream(hookParam.getStream());
+        RecordInfo recordInfo = RecordInfo.getInstance(hookParam);
+        mediaRecordMp4Event.setRecordInfo(recordInfo);
+        mediaRecordMp4Event.setMediaServer(mediaServer);
+        return mediaRecordMp4Event;
+    }
+
+    public RecordInfo getRecordInfo() {
+        return recordInfo;
+    }
+
+    public void setRecordInfo(RecordInfo recordInfo) {
+        this.recordInfo = recordInfo;
+    }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaRtpServerTimeoutEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaRtpServerTimeoutEvent.java
new file mode 100644
index 0000000..b700dd5
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaRtpServerTimeoutEvent.java
@@ -0,0 +1,22 @@
+package com.genersoft.iot.vmp.media.event.media;
+
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
+
+/**
+ * RtpServer鏀舵祦瓒呮椂浜嬩欢
+ */
+public class MediaRtpServerTimeoutEvent extends MediaEvent {
+    public MediaRtpServerTimeoutEvent(Object source) {
+        super(source);
+    }
+
+    public static MediaRtpServerTimeoutEvent getInstance(Object source, OnStreamChangedHookParam hookParam, MediaServer mediaServer){
+        MediaRtpServerTimeoutEvent mediaDepartureEven = new MediaRtpServerTimeoutEvent(source);
+        mediaDepartureEven.setApp(hookParam.getApp());
+        mediaDepartureEven.setStream(hookParam.getStream());
+        mediaDepartureEven.setSchema(hookParam.getSchema());
+        mediaDepartureEven.setMediaServer(mediaServer);
+        return mediaDepartureEven;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaSendRtpStoppedEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaSendRtpStoppedEvent.java
new file mode 100644
index 0000000..d37a4c2
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaSendRtpStoppedEvent.java
@@ -0,0 +1,52 @@
+package com.genersoft.iot.vmp.media.event.mediaServer;
+
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamNotFoundHookParam;
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * 鍙戦�佹祦鍋滄浜嬩欢
+ */
+public class MediaSendRtpStoppedEvent extends ApplicationEvent {
+    public MediaSendRtpStoppedEvent(Object source) {
+        super(source);
+    }
+
+    private String app;
+
+    private String stream;
+
+    private MediaServer mediaServer;
+
+    public static MediaSendRtpStoppedEvent getInstance(Object source, OnStreamNotFoundHookParam hookParam, MediaServer mediaServer){
+        MediaSendRtpStoppedEvent mediaDepartureEven = new MediaSendRtpStoppedEvent(source);
+        mediaDepartureEven.setApp(hookParam.getApp());
+        mediaDepartureEven.setStream(hookParam.getStream());
+        mediaDepartureEven.setMediaServer(mediaServer);
+        return mediaDepartureEven;
+    }
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public MediaServer getMediaServer() {
+        return mediaServer;
+    }
+
+    public void setMediaServer(MediaServer mediaServer) {
+        this.mediaServer = mediaServer;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerChangeEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerChangeEvent.java
new file mode 100644
index 0000000..ecbe332
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerChangeEvent.java
@@ -0,0 +1,34 @@
+package com.genersoft.iot.vmp.media.event.mediaServer;
+
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import org.springframework.context.ApplicationEvent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class MediaServerChangeEvent extends ApplicationEvent {
+
+    public MediaServerChangeEvent(Object source) {
+        super(source);
+    }
+
+    private List<MediaServer> mediaServerItemList;
+
+    public List<MediaServer> getMediaServerItemList() {
+        return mediaServerItemList;
+    }
+
+    public void setMediaServerItemList(List<MediaServer> mediaServerItemList) {
+        this.mediaServerItemList = mediaServerItemList;
+    }
+
+    public void setMediaServerItemList(MediaServer... mediaServerItemArray) {
+        this.mediaServerItemList = new ArrayList<>();
+        this.mediaServerItemList.addAll(Arrays.asList(mediaServerItemArray));
+    }
+
+    public void setMediaServerItem(List<MediaServer> mediaServerItemList) {
+        this.mediaServerItemList = mediaServerItemList;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerDeleteEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerDeleteEvent.java
new file mode 100755
index 0000000..a716ff0
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerDeleteEvent.java
@@ -0,0 +1,11 @@
+package com.genersoft.iot.vmp.media.event.mediaServer;
+
+/**
+ * zlm鍦ㄧ嚎浜嬩欢
+ */
+public class MediaServerDeleteEvent extends MediaServerEventAbstract {
+
+	public MediaServerDeleteEvent(Object source) {
+		super(source);
+	}
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMEventAbstract.java b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerEventAbstract.java
similarity index 62%
rename from src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMEventAbstract.java
rename to src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerEventAbstract.java
index 8ffbdde..a9bf769 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMEventAbstract.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerEventAbstract.java
@@ -1,9 +1,8 @@
-package com.genersoft.iot.vmp.media.zlm.event;
+package com.genersoft.iot.vmp.media.event.mediaServer;
 
-import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
 import org.springframework.context.ApplicationEvent;
 
-public abstract class ZLMEventAbstract extends ApplicationEvent {
+public abstract class MediaServerEventAbstract extends ApplicationEvent {
 
 
     private static final long serialVersionUID = 1L;
@@ -11,7 +10,7 @@
     private String mediaServerId;
 
 
-    public ZLMEventAbstract(Object source) {
+    public MediaServerEventAbstract(Object source) {
         super(source);
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerOfflineEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerOfflineEvent.java
new file mode 100755
index 0000000..2f9ac23
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerOfflineEvent.java
@@ -0,0 +1,11 @@
+package com.genersoft.iot.vmp.media.event.mediaServer;
+
+/**
+ * zlm绂荤嚎浜嬩欢绫�
+ */
+public class MediaServerOfflineEvent extends MediaServerEventAbstract {
+
+	public MediaServerOfflineEvent(Object source) {
+		super(source);
+	}
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerOnlineEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerOnlineEvent.java
new file mode 100755
index 0000000..673dce4
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerOnlineEvent.java
@@ -0,0 +1,11 @@
+package com.genersoft.iot.vmp.media.event.mediaServer;
+
+/**
+ * zlm鍦ㄧ嚎浜嬩欢
+ */
+public class MediaServerOnlineEvent extends MediaServerEventAbstract {
+
+	public MediaServerOnlineEvent(Object source) {
+		super(source);
+	}
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java
similarity index 70%
rename from src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java
rename to src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java
index bad8e56..2413f56 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java
@@ -1,6 +1,5 @@
-package com.genersoft.iot.vmp.media.zlm.event;
+package com.genersoft.iot.vmp.media.event.mediaServer;
 
-import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IPlayService;
 import com.genersoft.iot.vmp.service.IStreamProxyService;
 import com.genersoft.iot.vmp.service.IStreamPushService;
@@ -20,9 +19,9 @@
  * @date: 2020骞�5鏈�6鏃� 涓嬪崍1:51:23
  */
 @Component
-public class ZLMStatusEventListener {
+public class MediaServerStatusEventListener {
 	
-	private final static Logger logger = LoggerFactory.getLogger(ZLMStatusEventListener.class);
+	private final static Logger logger = LoggerFactory.getLogger(MediaServerStatusEventListener.class);
 
 	@Autowired
 	private IStreamPushService streamPushService;
@@ -31,15 +30,12 @@
 	private IStreamProxyService streamProxyService;
 
 	@Autowired
-	private IMediaServerService mediaServerService;
-
-	@Autowired
 	private IPlayService playService;
 
 	@Async("taskExecutor")
 	@EventListener
-	public void onApplicationEvent(ZLMOnlineEvent event) {
-		logger.info("[ZLM] 涓婄嚎 ID锛�" + event.getMediaServerId());
+	public void onApplicationEvent(MediaServerOnlineEvent event) {
+		logger.info("[濯掍綋鑺傜偣] 涓婄嚎 ID锛�" + event.getMediaServerId());
 		streamPushService.zlmServerOnline(event.getMediaServerId());
 		streamProxyService.zlmServerOnline(event.getMediaServerId());
 		playService.zlmServerOnline(event.getMediaServerId());
@@ -47,11 +43,10 @@
 
 	@Async("taskExecutor")
 	@EventListener
-	public void onApplicationEvent(ZLMOfflineEvent event) {
+	public void onApplicationEvent(MediaServerOfflineEvent event) {
 
-		logger.info("[ZLM] 绂荤嚎锛孖D锛�" + event.getMediaServerId());
+		logger.info("[濯掍綋鑺傜偣] 绂荤嚎锛孖D锛�" + event.getMediaServerId());
 		// 澶勭悊ZLM绂荤嚎
-		mediaServerService.zlmServerOffline(event.getMediaServerId());
 		streamProxyService.zlmServerOffline(event.getMediaServerId());
 		streamPushService.zlmServerOffline(event.getMediaServerId());
 		playService.zlmServerOffline(event.getMediaServerId());
diff --git a/src/main/java/com/genersoft/iot/vmp/media/service/IMediaNodeServerService.java b/src/main/java/com/genersoft/iot/vmp/media/service/IMediaNodeServerService.java
new file mode 100644
index 0000000..8739938
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/service/IMediaNodeServerService.java
@@ -0,0 +1,61 @@
+package com.genersoft.iot.vmp.media.service;
+
+import com.genersoft.iot.vmp.common.CommonCallback;
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
+
+import java.util.List;
+import java.util.Map;
+
+public interface IMediaNodeServerService {
+    int createRTPServer(MediaServer mediaServer, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode);
+
+    void closeRtpServer(MediaServer mediaServer, String streamId);
+
+    void closeRtpServer(MediaServer mediaServer, String streamId, CommonCallback<Boolean> callback);
+
+    void closeStreams(MediaServer mediaServer, String app, String stream);
+
+    Boolean updateRtpServerSSRC(MediaServer mediaServer, String stream, String ssrc);
+
+    boolean checkNodeId(MediaServer mediaServer);
+
+    void online(MediaServer mediaServer);
+
+    MediaServer checkMediaServer(String ip, int port, String secret);
+
+    boolean stopSendRtp(MediaServer mediaInfo, String app, String stream, String ssrc);
+
+    boolean deleteRecordDirectory(MediaServer mediaServer, String app, String stream, String date, String fileName);
+
+    List<StreamInfo> getMediaList(MediaServer mediaServer, String app, String stream, String callId);
+
+    Boolean connectRtpServer(MediaServer mediaServer, String address, int port, String stream);
+
+    void getSnap(MediaServer mediaServer, String streamUrl, int timeoutSec, int expireSec, String path, String fileName);
+
+    MediaInfo getMediaInfo(MediaServer mediaServer, String app, String stream);
+
+    Boolean pauseRtpCheck(MediaServer mediaServer, String streamKey);
+
+    Boolean resumeRtpCheck(MediaServer mediaServer, String streamKey);
+
+    String getFfmpegCmd(MediaServer mediaServer, String cmdKey);
+
+    WVPResult<String> addFFmpegSource(MediaServer mediaServer, String srcUrl, String dstUrl, int timeoutMs, boolean enableAudio, boolean enableMp4, String ffmpegCmdKey);
+
+    WVPResult<String> addStreamProxy(MediaServer mediaServer, String app, String stream, String url, boolean enableAudio, boolean enableMp4, String rtpType);
+
+    Boolean delFFmpegSource(MediaServer mediaServer, String streamKey);
+
+    Boolean delStreamProxy(MediaServer mediaServer, String streamKey);
+
+    Map<String, String> getFFmpegCMDs(MediaServer mediaServer);
+
+    void startSendRtpPassive(MediaServer mediaServer, SendRtpItem sendRtpItem, Integer timeout);
+
+    void startSendRtpStream(MediaServer mediaServer, SendRtpItem sendRtpItem);
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/service/IMediaServerService.java b/src/main/java/com/genersoft/iot/vmp/media/service/IMediaServerService.java
new file mode 100755
index 0000000..fb56ab6
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/service/IMediaServerService.java
@@ -0,0 +1,145 @@
+package com.genersoft.iot.vmp.media.service;
+
+import com.genersoft.iot.vmp.common.CommonCallback;
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
+import com.genersoft.iot.vmp.service.bean.SSRCInfo;
+import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 濯掍綋鏈嶅姟鑺傜偣
+ */
+public interface IMediaServerService {
+
+    List<MediaServer> getAllOnlineList();
+
+    List<MediaServer> getAll();
+
+    List<MediaServer> getAllFromDatabase();
+
+    List<MediaServer> getAllOnline();
+
+    MediaServer getOne(String generalMediaServerId);
+
+    void syncCatchFromDatabase();
+
+    MediaServer getMediaServerForMinimumLoad(Boolean hasAssist);
+
+    void updateVmServer(List<MediaServer>  mediaServerItemList);
+
+    SSRCInfo openRTPServer(MediaServer mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck,
+                           boolean isPlayback, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode);
+
+    void closeRTPServer(MediaServer mediaServerItem, String streamId);
+
+    void closeRTPServer(MediaServer mediaServerItem, String streamId, CommonCallback<Boolean> callback);
+    Boolean updateRtpServerSSRC(MediaServer mediaServerItem, String streamId, String ssrc);
+
+    void closeRTPServer(String mediaServerId, String streamId);
+
+    void clearRTPServer(MediaServer mediaServerItem);
+
+    void update(MediaServer mediaSerItem);
+
+    void addCount(String mediaServerId);
+
+    void removeCount(String mediaServerId);
+
+    void releaseSsrc(String mediaServerItemId, String ssrc);
+
+    void clearMediaServerForOnline();
+
+    void add(MediaServer mediaSerItem);
+
+    void resetOnlineServerItem(MediaServer serverItem);
+
+    MediaServer checkMediaServer(String ip, int port, String secret, String type);
+
+    boolean checkMediaRecordServer(String ip, int port);
+
+    void delete(String id);
+
+    MediaServer getDefaultMediaServer();
+
+    MediaServerLoad getLoad(MediaServer mediaServerItem);
+
+    List<MediaServer> getAllWithAssistPort();
+
+    MediaServer getOneFromDatabase(String id);
+
+    boolean stopSendRtp(MediaServer mediaInfo, String app, String stream, String ssrc);
+
+    boolean deleteRecordDirectory(MediaServer mediaServerItem, String app, String stream, String date, String fileName);
+
+    List<StreamInfo> getMediaList(MediaServer mediaInfo, String app, String stream, String callId);
+
+    Boolean connectRtpServer(MediaServer mediaServerItem, String address, int port, String stream);
+
+    void getSnap(MediaServer mediaServerItemInuse, String streamUrl, int timeoutSec, int expireSec, String path, String fileName);
+
+    MediaInfo getMediaInfo(MediaServer mediaServerItem, String app, String stream);
+
+    Boolean pauseRtpCheck(MediaServer mediaServerItem, String streamKey);
+
+    boolean resumeRtpCheck(MediaServer mediaServerItem, String streamKey);
+
+    String getFfmpegCmd(MediaServer mediaServer, String cmdKey);
+
+    void closeStreams(MediaServer mediaServerItem, String app, String stream);
+
+    WVPResult<String> addFFmpegSource(MediaServer mediaServerItem, String srcUrl, String dstUrl, int timeoutMs, boolean enableAudio, boolean enableMp4, String ffmpegCmdKey);
+
+    WVPResult<String> addStreamProxy(MediaServer mediaServerItem, String app, String stream, String url, boolean enableAudio, boolean enableMp4, String rtpType);
+
+    Boolean delFFmpegSource(MediaServer mediaServerItem, String streamKey);
+
+    Boolean delStreamProxy(MediaServer mediaServerItem, String streamKey);
+
+    Map<String, String> getFFmpegCMDs(MediaServer mediaServer);
+
+    /**
+     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 閫氳繃zlm鎺ュ彛妫�鏌ユ槸鍚﹀瓨鍦�
+     * @param app
+     * @param stream
+     * @return
+     */
+    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId,String addr, boolean authority);
+
+
+    /**
+     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 閫氳繃zlm鎺ュ彛妫�鏌ユ槸鍚﹀瓨鍦�, 杩斿洖鐨刬p浣跨敤杩滅▼璁块棶ip锛岄�傜敤涓巣lm涓巜vp鍦ㄤ竴鍙颁富鏈虹殑鎯呭喌
+     * @param app
+     * @param stream
+     * @return
+     */
+    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, boolean authority);
+
+    /**
+     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 鍙槸鍦板潃鎷兼帴
+     * @param app
+     * @param stream
+     * @return
+     */
+    StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServerItem, String app, String stream, MediaInfo mediaInfo, String callId);
+
+    /**
+     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 鍙槸鍦板潃鎷兼帴锛岃繑鍥炵殑ip浣跨敤杩滅▼璁块棶ip锛岄�傜敤涓巣lm涓巜vp鍦ㄤ竴鍙颁富鏈虹殑鎯呭喌
+     * @param app
+     * @param stream
+     * @return
+     */
+    StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServer, String app, String stream, MediaInfo mediaInfo, String addr, String callId, boolean isPlay);
+
+    Boolean isStreamReady(MediaServer mediaServer, String rtp, String streamId);
+
+    void startSendRtpPassive(MediaServer mediaServer, ParentPlatform platform, SendRtpItem sendRtpItem, Integer timeout);
+
+    void startSendRtpStream(MediaServer mediaServer, ParentPlatform platform, SendRtpItem sendRtpItem);
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java
new file mode 100755
index 0000000..6214ccb
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java
@@ -0,0 +1,837 @@
+package com.genersoft.iot.vmp.media.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.genersoft.iot.vmp.common.CommonCallback;
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.common.VideoManagerConstants;
+import com.genersoft.iot.vmp.conf.MediaConfig;
+import com.genersoft.iot.vmp.conf.UserSetting;
+import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.gb28181.bean.InviteStreamType;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
+import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
+import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
+import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent;
+import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerChangeEvent;
+import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerDeleteEvent;
+import com.genersoft.iot.vmp.media.service.IMediaNodeServerService;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
+import com.genersoft.iot.vmp.service.IInviteStreamService;
+import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
+import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
+import com.genersoft.iot.vmp.service.bean.SSRCInfo;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
+import com.genersoft.iot.vmp.storager.dao.MediaServerMapper;
+import com.genersoft.iot.vmp.utils.DateUtil;
+import com.genersoft.iot.vmp.utils.JsonUtil;
+import com.genersoft.iot.vmp.utils.redis.RedisUtil;
+import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
+import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.event.EventListener;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.util.ObjectUtils;
+
+import java.time.LocalDateTime;
+import java.util.*;
+
+/**
+ * 濯掍綋鏈嶅姟鍣ㄨ妭鐐圭鐞�
+ */
+@Service
+@DS("master")
+public class MediaServerServiceImpl implements IMediaServerService {
+
+    private final static Logger logger = LoggerFactory.getLogger(MediaServerServiceImpl.class);
+
+    @Autowired
+    private SSRCFactory ssrcFactory;
+
+    @Autowired
+    private UserSetting userSetting;
+
+    @Autowired
+    private MediaServerMapper mediaServerMapper;
+
+    @Autowired
+    private IRedisCatchStorage redisCatchStorage;
+
+    @Autowired
+    private IInviteStreamService inviteStreamService;
+
+    @Autowired
+    private RedisTemplate<Object, Object> redisTemplate;
+
+    @Autowired
+    private Map<String, IMediaNodeServerService> nodeServerServiceMap;
+
+    @Autowired
+    private ApplicationEventPublisher applicationEventPublisher;
+
+    @Autowired
+    private MediaConfig mediaConfig;
+
+
+
+    /**
+     * 娴佸埌鏉ョ殑澶勭悊
+     */
+    @Async("taskExecutor")
+    @org.springframework.context.event.EventListener
+    public void onApplicationEvent(MediaArrivalEvent event) {
+        if ("rtsp".equals(event.getSchema())) {
+            logger.info("娴佸彉鍖栵細娉ㄥ唽 app->{}, stream->{}", event.getApp(), event.getStream());
+            addCount(event.getMediaServer().getId());
+        }
+    }
+
+    /**
+     * 娴佺寮�鐨勫鐞�
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaDepartureEvent event) {
+        if ("rtsp".equals(event.getSchema())) {
+            logger.info("娴佸彉鍖栵細娉ㄩ攢, app->{}, stream->{}", event.getApp(), event.getStream());
+            removeCount(event.getMediaServer().getId());
+        }
+    }
+
+
+    /**
+     * 鍒濆鍖�
+     */
+    @Override
+    public void updateVmServer(List<MediaServer> mediaServerList) {
+        logger.info("[濯掍綋鏈嶅姟鑺傜偣] 缂撳瓨鍒濆鍖� ");
+        for (MediaServer mediaServer : mediaServerList) {
+            if (ObjectUtils.isEmpty(mediaServer.getId())) {
+                continue;
+            }
+            // 鏇存柊
+            if (!ssrcFactory.hasMediaServerSSRC(mediaServer.getId())) {
+                ssrcFactory.initMediaServerSSRC(mediaServer.getId(), null);
+            }
+            // 鏌ヨredis鏄惁瀛樺湪姝ediaServer
+            String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + mediaServer.getId();
+            Boolean hasKey = redisTemplate.hasKey(key);
+            if (hasKey != null && ! hasKey) {
+                redisTemplate.opsForValue().set(key, mediaServer);
+            }
+        }
+    }
+
+
+    @Override
+    public SSRCInfo openRTPServer(MediaServer mediaServer, String streamId, String presetSsrc, boolean ssrcCheck,
+                                  boolean isPlayback, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode) {
+        if (mediaServer == null || mediaServer.getId() == null) {
+            logger.info("[openRTPServer] 澶辫触, mediaServer == null || mediaServer.getId() == null");
+            return null;
+        }
+        // 鑾峰彇mediaServer鍙敤鐨剆src
+        String ssrc;
+        if (presetSsrc != null) {
+            ssrc = presetSsrc;
+        }else {
+            if (isPlayback) {
+                ssrc = ssrcFactory.getPlayBackSsrc(mediaServer.getId());
+            }else {
+                ssrc = ssrcFactory.getPlaySsrc(mediaServer.getId());
+            }
+        }
+
+        if (streamId == null) {
+            streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase();
+        }
+        if (ssrcCheck && tcpMode > 0) {
+            // 鐩墠zlm涓嶆敮鎸� tcp妯″紡鏇存柊ssrc锛屾殏鏃跺叧闂璼src鏍¢獙
+            logger.warn("[openRTPServer] 骞冲彴瀵规帴鏃朵笅绾у彲鑳借嚜瀹氫箟ssrc锛屼絾鏄痶cp妯″紡zlm鏀舵祦鐩墠鏃犳硶鏇存柊ssrc锛屽彲鑳芥敹娴佽秴鏃讹紝姝ゆ椂璇蜂娇鐢╱dp鏀舵祦鎴栬�呭叧闂璼src鏍¢獙");
+        }
+        int rtpServerPort;
+        if (mediaServer.isRtpEnable()) {
+            IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+            if (mediaNodeServerService == null) {
+                logger.info("[openRTPServer] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+                return null;
+            }
+            rtpServerPort = mediaNodeServerService.createRTPServer(mediaServer, streamId, ssrcCheck ? Long.parseLong(ssrc) : 0, port, onlyAuto, disableAudio, reUsePort, tcpMode);
+        } else {
+            rtpServerPort = mediaServer.getRtpProxyPort();
+        }
+        return new SSRCInfo(rtpServerPort, ssrc, streamId);
+    }
+
+    @Override
+    public void closeRTPServer(MediaServer mediaServer, String streamId) {
+        if (mediaServer == null) {
+            return;
+        }
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[closeRTPServer] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return;
+        }
+        mediaNodeServerService.closeRtpServer(mediaServer, streamId);
+    }
+
+    @Override
+    public void closeRTPServer(MediaServer mediaServer, String streamId, CommonCallback<Boolean> callback) {
+        if (mediaServer == null) {
+            callback.run(false);
+            return;
+        }
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[closeRTPServer] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return;
+        }
+        mediaNodeServerService.closeRtpServer(mediaServer, streamId, callback);
+    }
+
+    @Override
+    public void closeRTPServer(String mediaServerId, String streamId) {
+        MediaServer mediaServer = this.getOne(mediaServerId);
+        if (mediaServer == null) {
+            return;
+        }
+        if (mediaServer.isRtpEnable()) {
+            closeRTPServer(mediaServer, streamId);
+        }
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[closeRTPServer] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return;
+        }
+        mediaNodeServerService.closeStreams(mediaServer, "rtp", streamId);
+    }
+
+    @Override
+    public Boolean updateRtpServerSSRC(MediaServer mediaServer, String streamId, String ssrc) {
+        if (mediaServer == null) {
+            return false;
+        }
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[updateRtpServerSSRC] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return false;
+        }
+        return mediaNodeServerService.updateRtpServerSSRC(mediaServer, streamId, ssrc);
+    }
+
+    @Override
+    public void releaseSsrc(String mediaServerId, String ssrc) {
+        MediaServer mediaServer = getOne(mediaServerId);
+        if (mediaServer == null || ssrc == null) {
+            return;
+        }
+        ssrcFactory.releaseSsrc(mediaServerId, ssrc);
+    }
+
+    /**
+     * 濯掍綋鏈嶅姟鑺傜偣 閲嶅惎鍚庨噸缃粬鐨勬帹娴佷俊鎭紝 TODO 缁欐鍦ㄤ娇鐢ㄧ殑璁惧鍙戦�佸仠姝㈠懡浠�
+     */
+    @Override
+    public void clearRTPServer(MediaServer mediaServer) {
+        ssrcFactory.reset(mediaServer.getId());
+    }
+
+
+    @Override
+    public void update(MediaServer mediaSerItem) {
+        mediaServerMapper.update(mediaSerItem);
+        MediaServer mediaServerInRedis = getOne(mediaSerItem.getId());
+        MediaServer mediaServerInDataBase = mediaServerMapper.queryOne(mediaSerItem.getId());
+        if (mediaServerInDataBase == null) {
+            return;
+        }
+        mediaServerInDataBase.setStatus(mediaSerItem.isStatus());
+        if (mediaServerInRedis == null || !ssrcFactory.hasMediaServerSSRC(mediaServerInDataBase.getId())) {
+            ssrcFactory.initMediaServerSSRC(mediaServerInDataBase.getId(),null);
+        }
+        String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + mediaServerInDataBase.getId();
+        redisTemplate.opsForValue().set(key, mediaServerInDataBase);
+        if (mediaServerInDataBase.isStatus()) {
+            resetOnlineServerItem(mediaServerInDataBase);
+        }else {
+            // 鍙戦�佷簨浠�
+            MediaServerChangeEvent event = new MediaServerChangeEvent(this);
+            event.setMediaServerItemList(mediaServerInDataBase);
+            applicationEventPublisher.publishEvent(event);
+        }
+    }
+
+
+    @Override
+    public List<MediaServer> getAllOnlineList() {
+        List<MediaServer> result = new ArrayList<>();
+        List<Object> mediaServerKeys = RedisUtil.scan(redisTemplate, String.format("%S*", VideoManagerConstants.MEDIA_SERVER_PREFIX+ userSetting.getServerId() + ":" ));
+        String onlineKey = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
+        for (Object mediaServerKey : mediaServerKeys) {
+            String key = (String) mediaServerKey;
+            MediaServer mediaServer = JsonUtil.redisJsonToObject(redisTemplate, key, MediaServer.class);
+            if (Objects.isNull(mediaServer)) {
+                continue;
+            }
+            // 妫�鏌ョ姸鎬�
+            Double aDouble = redisTemplate.opsForZSet().score(onlineKey, mediaServer.getId());
+            if (aDouble != null) {
+                mediaServer.setStatus(true);
+            }
+            result.add(mediaServer);
+        }
+        result.sort((serverItem1, serverItem2)->{
+            int sortResult = 0;
+            LocalDateTime localDateTime1 = LocalDateTime.parse(serverItem1.getCreateTime(), DateUtil.formatter);
+            LocalDateTime localDateTime2 = LocalDateTime.parse(serverItem2.getCreateTime(), DateUtil.formatter);
+
+            sortResult = localDateTime1.compareTo(localDateTime2);
+            return  sortResult;
+        });
+        return result;
+    }
+
+    @Override
+    public List<MediaServer> getAll() {
+        List<MediaServer> mediaServerList = mediaServerMapper.queryAll();
+        if (mediaServerList.isEmpty()) {
+            return new ArrayList<>();
+        }
+        for (MediaServer mediaServer : mediaServerList) {
+            MediaServer mediaServerInRedis = getOne(mediaServer.getId());
+            if (mediaServerInRedis != null) {
+                mediaServer.setStatus(mediaServerInRedis.isStatus());
+            }
+        }
+        return mediaServerList;
+    }
+
+
+    @Override
+    public List<MediaServer> getAllFromDatabase() {
+        return mediaServerMapper.queryAll();
+    }
+
+    @Override
+    public List<MediaServer> getAllOnline() {
+        String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
+        Set<Object> mediaServerIdSet = redisTemplate.opsForZSet().reverseRange(key, 0, -1);
+
+        List<MediaServer> result = new ArrayList<>();
+        if (mediaServerIdSet != null && mediaServerIdSet.size() > 0) {
+            for (Object mediaServerId : mediaServerIdSet) {
+                String mediaServerIdStr = (String) mediaServerId;
+                String serverKey = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + mediaServerIdStr;
+                result.add((MediaServer) redisTemplate.opsForValue().get(serverKey));
+            }
+        }
+        Collections.reverse(result);
+        return result;
+    }
+
+    /**
+     * 鑾峰彇鍗曚釜濯掍綋鏈嶅姟鑺傜偣鏈嶅姟鍣�
+     * @param mediaServerId 鏈嶅姟id
+     * @return mediaServer
+     */
+    @Override
+    public MediaServer getOne(String mediaServerId) {
+        if (mediaServerId == null) {
+            return null;
+        }
+        String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + mediaServerId;
+        return JsonUtil.redisJsonToObject(redisTemplate, key, MediaServer.class);
+    }
+
+
+    @Override
+    public MediaServer getDefaultMediaServer() {
+        return mediaServerMapper.queryDefault();
+    }
+
+    @Override
+    public void clearMediaServerForOnline() {
+        String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
+        redisTemplate.delete(key);
+    }
+
+    @Override
+    public void add(MediaServer mediaServer) {
+        mediaServer.setCreateTime(DateUtil.getNow());
+        mediaServer.setUpdateTime(DateUtil.getNow());
+        if (mediaServer.getHookAliveInterval() == null || mediaServer.getHookAliveInterval() == 0F) {
+            mediaServer.setHookAliveInterval(10F);
+        }
+        if (mediaServer.getType() == null) {
+            logger.info("[娣诲姞濯掍綋鑺傜偣] 澶辫触, mediaServer鐨勭被鍨嬶細涓虹┖");
+            return;
+        }
+        if (mediaServerMapper.queryOne(mediaServer.getId()) != null) {
+            logger.info("[娣诲姞濯掍綋鑺傜偣] 澶辫触, 濯掍綋鏈嶅姟ID宸插瓨鍦紝璇蜂慨鏀瑰獟浣撴湇鍔″櫒閰嶇疆, {}", mediaServer.getId());
+            throw new ControllerException(ErrorCode.ERROR100.getCode(),"淇濆瓨澶辫触锛屽獟浣撴湇鍔D [ " + mediaServer.getId() + " ] 宸插瓨鍦紝璇蜂慨鏀瑰獟浣撴湇鍔″櫒閰嶇疆");
+        }
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[娣诲姞濯掍綋鑺傜偣] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return;
+        }
+        mediaServerMapper.add(mediaServer);
+        if (mediaServer.isStatus()) {
+            mediaNodeServerService.online(mediaServer);
+        }else {
+            // 鍙戦�佷簨浠�
+            MediaServerChangeEvent event = new MediaServerChangeEvent(this);
+            event.setMediaServerItemList(mediaServer);
+            applicationEventPublisher.publishEvent(event);
+        }
+    }
+
+    @Override
+    public void resetOnlineServerItem(MediaServer serverItem) {
+        // 鏇存柊缂撳瓨
+        String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
+        // 浣跨敤zset鐨勫垎鏁颁綔涓哄綋鍓嶅苟鍙戦噺锛� 榛樿鍊艰缃负0
+        if (redisTemplate.opsForZSet().score(key, serverItem.getId()) == null) {  // 涓嶅瓨鍦ㄥ垯璁剧疆榛樿鍊� 宸插瓨鍦ㄥ垯閲嶇疆
+            redisTemplate.opsForZSet().add(key, serverItem.getId(), 0L);
+            // 鏌ヨ鏈嶅姟娴佹暟閲�
+            int count = getMediaList(serverItem);
+            redisTemplate.opsForZSet().add(key, serverItem.getId(), count);
+        }else {
+            clearRTPServer(serverItem);
+        }
+    }
+
+    private int getMediaList(MediaServer serverItem) {
+
+        return 0;
+    }
+
+
+    @Override
+    public void addCount(String mediaServerId) {
+        if (mediaServerId == null) {
+            return;
+        }
+        String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
+        redisTemplate.opsForZSet().incrementScore(key, mediaServerId, 1);
+
+    }
+
+    @Override
+    public void removeCount(String mediaServerId) {
+        String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
+        redisTemplate.opsForZSet().incrementScore(key, mediaServerId, - 1);
+    }
+
+    /**
+     * 鑾峰彇璐熻浇鏈�浣庣殑鑺傜偣
+     * @return mediaServer
+     */
+    @Override
+    public MediaServer getMediaServerForMinimumLoad(Boolean hasAssist) {
+        String key = VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId();
+        Long size = redisTemplate.opsForZSet().zCard(key);
+        if (size  == null || size == 0) {
+            logger.info("鑾峰彇璐熻浇鏈�浣庣殑鑺傜偣鏃舵棤鍦ㄧ嚎鑺傜偣");
+            return null;
+        }
+
+        // 鑾峰彇鍒嗘暟鏈�浣庣殑锛屽強骞跺彂鏈�浣庣殑
+        Set<Object> objects = redisTemplate.opsForZSet().range(key, 0, -1);
+        ArrayList<Object> mediaServerObjectS = new ArrayList<>(objects);
+        MediaServer mediaServer = null;
+        if (hasAssist == null) {
+            String mediaServerId = (String)mediaServerObjectS.get(0);
+            mediaServer = getOne(mediaServerId);
+        }else if (hasAssist) {
+            for (Object mediaServerObject : mediaServerObjectS) {
+                String mediaServerId = (String)mediaServerObject;
+                MediaServer serverItem = getOne(mediaServerId);
+                if (serverItem.getRecordAssistPort() > 0) {
+                    mediaServer = serverItem;
+                    break;
+                }
+            }
+        }else if (!hasAssist) {
+            for (Object mediaServerObject : mediaServerObjectS) {
+                String mediaServerId = (String)mediaServerObject;
+                MediaServer serverItem = getOne(mediaServerId);
+                if (serverItem.getRecordAssistPort() == 0) {
+                    mediaServer = serverItem;
+                    break;
+                }
+            }
+        }
+
+        return mediaServer;
+    }
+
+    @Override
+    public MediaServer checkMediaServer(String ip, int port, String secret, String type) {
+        if (mediaServerMapper.queryOneByHostAndPort(ip, port) != null) {
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "姝よ繛鎺ュ凡瀛樺湪");
+        }
+
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(type);
+        if (mediaNodeServerService == null) {
+            logger.info("[closeRTPServer] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", type);
+            return null;
+        }
+        MediaServer mediaServer = mediaNodeServerService.checkMediaServer(ip, port, secret);
+        if (mediaServer != null) {
+            if (mediaServerMapper.queryOne(mediaServer.getId()) != null) {
+                throw new ControllerException(ErrorCode.ERROR100.getCode(), "濯掍綋鏈嶅姟ID [" + mediaServer.getId() + " ] 宸插瓨鍦紝璇蜂慨鏀瑰獟浣撴湇鍔″櫒閰嶇疆");
+            }
+        }
+        return mediaServer;
+    }
+
+    @Override
+    public boolean checkMediaRecordServer(String ip, int port) {
+        boolean result = false;
+        OkHttpClient client = new OkHttpClient();
+        String url = String.format("http://%s:%s/index/api/record",  ip, port);
+        Request request = new Request.Builder()
+                .get()
+                .url(url)
+                .build();
+        try {
+            Response response = client.newCall(request).execute();
+            if (response != null) {
+                result = true;
+            }
+        } catch (Exception e) {}
+
+        return result;
+    }
+
+    @Override
+    public void delete(String id) {
+        mediaServerMapper.delOne(id);
+        redisTemplate.opsForZSet().remove(VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId(), id);
+        String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + id;
+        redisTemplate.delete(key);
+        // 鍙戦�佽妭鐐圭Щ闄ら�氱煡
+        MediaServerDeleteEvent event = new MediaServerDeleteEvent(this);
+        event.setMediaServerId(id);
+        applicationEventPublisher.publishEvent(event);
+    }
+
+    @Override
+    public MediaServer getOneFromDatabase(String mediaServerId) {
+        return mediaServerMapper.queryOne(mediaServerId);
+    }
+
+    @Override
+    public void syncCatchFromDatabase() {
+        List<MediaServer> allInCatch = getAllOnlineList();
+        List<MediaServer> allInDatabase = mediaServerMapper.queryAll();
+        Map<String, MediaServer> mediaServerMap = new HashMap<>();
+
+        for (MediaServer mediaServer : allInDatabase) {
+            mediaServerMap.put(mediaServer.getId(), mediaServer);
+        }
+        for (MediaServer mediaServer : allInCatch) {
+            // 娓呴櫎鏁版嵁涓笉瀛樺湪浣唕edis缂撳瓨鏁版嵁
+            if (!mediaServerMap.containsKey(mediaServer.getId())) {
+                delete(mediaServer.getId());
+            }
+        }
+    }
+
+    @Override
+    public MediaServerLoad getLoad(MediaServer mediaServer) {
+        MediaServerLoad result = new MediaServerLoad();
+        result.setId(mediaServer.getId());
+        result.setPush(redisCatchStorage.getPushStreamCount(mediaServer.getId()));
+        result.setProxy(redisCatchStorage.getProxyStreamCount(mediaServer.getId()));
+
+        result.setGbReceive(inviteStreamService.getStreamInfoCount(mediaServer.getId()));
+        result.setGbSend(redisCatchStorage.getGbSendCount(mediaServer.getId()));
+        return result;
+    }
+
+    @Override
+    public List<MediaServer> getAllWithAssistPort() {
+        return mediaServerMapper.queryAllWithAssistPort();
+    }
+
+
+    @Override
+    public boolean stopSendRtp(MediaServer mediaInfo, String app, String stream, String ssrc) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaInfo.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[stopSendRtp] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaInfo.getType());
+            return false;
+        }
+        return mediaNodeServerService.stopSendRtp(mediaInfo, app, stream, ssrc);
+    }
+
+    @Override
+    public boolean deleteRecordDirectory(MediaServer mediaServer, String app, String stream, String date, String fileName) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[stopSendRtp] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return false;
+        }
+        return mediaNodeServerService.deleteRecordDirectory(mediaServer, app, stream, date, fileName);
+    }
+
+    @Override
+    public List<StreamInfo> getMediaList(MediaServer mediaServer, String app, String stream, String callId) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[getMediaList] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return new ArrayList<>();
+        }
+        return mediaNodeServerService.getMediaList(mediaServer, app, stream, callId);
+    }
+
+    @Override
+    public Boolean connectRtpServer(MediaServer mediaServer, String address, int port, String stream) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[connectRtpServer] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return false;
+        }
+        return mediaNodeServerService.connectRtpServer(mediaServer, address, port, stream);
+    }
+
+    @Override
+    public void getSnap(MediaServer mediaServer, String streamUrl, int timeoutSec, int expireSec, String path, String fileName) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[getSnap] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return;
+        }
+        mediaNodeServerService.getSnap(mediaServer, streamUrl, timeoutSec, expireSec, path, fileName);
+    }
+
+    @Override
+    public MediaInfo getMediaInfo(MediaServer mediaServer, String app, String stream) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[getMediaInfo] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return null;
+        }
+        return mediaNodeServerService.getMediaInfo(mediaServer, app, stream);
+    }
+
+    @Override
+    public Boolean pauseRtpCheck(MediaServer mediaServer, String streamKey) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[pauseRtpCheck] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return false;
+        }
+        return mediaNodeServerService.pauseRtpCheck(mediaServer, streamKey);
+    }
+
+    @Override
+    public boolean resumeRtpCheck(MediaServer mediaServer, String streamKey) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[pauseRtpCheck] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return false;
+        }
+        return mediaNodeServerService.resumeRtpCheck(mediaServer, streamKey);
+    }
+
+    @Override
+    public String getFfmpegCmd(MediaServer mediaServer, String cmdKey) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[getFfmpegCmd] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return null;
+        }
+        return mediaNodeServerService.getFfmpegCmd(mediaServer, cmdKey);
+    }
+
+    @Override
+    public void closeStreams(MediaServer mediaServer, String app, String stream) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[closeStreams] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return;
+        }
+        mediaNodeServerService.closeStreams(mediaServer, app, stream);
+    }
+
+    @Override
+    public WVPResult<String> addFFmpegSource(MediaServer mediaServer, String srcUrl, String dstUrl, int timeoutMs, boolean enableAudio, boolean enableMp4, String ffmpegCmdKey) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[addFFmpegSource] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return WVPResult.fail(ErrorCode.ERROR400);
+        }
+        return mediaNodeServerService.addFFmpegSource(mediaServer, srcUrl, dstUrl, timeoutMs, enableAudio, enableMp4, ffmpegCmdKey);
+    }
+
+    @Override
+    public WVPResult<String> addStreamProxy(MediaServer mediaServer, String app, String stream, String url, boolean enableAudio, boolean enableMp4, String rtpType) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[addStreamProxy] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return WVPResult.fail(ErrorCode.ERROR400);
+        }
+        return mediaNodeServerService.addStreamProxy(mediaServer, app, stream, url, enableAudio, enableMp4, rtpType);
+    }
+
+    @Override
+    public Boolean delFFmpegSource(MediaServer mediaServer, String streamKey) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[delFFmpegSource] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return false;
+        }
+        return mediaNodeServerService.delFFmpegSource(mediaServer, streamKey);
+    }
+
+    @Override
+    public Boolean delStreamProxy(MediaServer mediaServerItem, String streamKey) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServerItem.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[delStreamProxy] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServerItem.getType());
+            return false;
+        }
+        return mediaNodeServerService.delStreamProxy(mediaServerItem, streamKey);
+    }
+
+    @Override
+    public Map<String, String> getFFmpegCMDs(MediaServer mediaServer) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[getFFmpegCMDs] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return new HashMap<>();
+        }
+        return mediaNodeServerService.getFFmpegCMDs(mediaServer);
+    }
+
+    @Override
+    public StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServerItem, String app, String stream, MediaInfo mediaInfo, String callId) {
+        return getStreamInfoByAppAndStream(mediaServerItem, app, stream, mediaInfo, null, callId, true);
+    }
+
+    @Override
+    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, String addr, boolean authority) {
+        StreamInfo streamInfo = null;
+        if (mediaServerId == null) {
+            mediaServerId = mediaConfig.getId();
+        }
+        MediaServer mediaInfo = getOne(mediaServerId);
+        if (mediaInfo == null) {
+            return null;
+        }
+        String calld = null;
+        StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
+        if (streamAuthorityInfo != null) {
+            calld = streamAuthorityInfo.getCallId();
+        }
+        List<StreamInfo> streamInfoList = getMediaList(mediaInfo, app, stream, calld);
+        if (streamInfoList.isEmpty()) {
+            return null;
+        }else {
+            return streamInfoList.get(0);
+        }
+    }
+
+
+
+    @Override
+    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, boolean authority) {
+        return getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, null, authority);
+    }
+
+    @Override
+    public StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServer, String app, String stream, MediaInfo mediaInfo, String addr, String callId, boolean isPlay) {
+        StreamInfo streamInfoResult = new StreamInfo();
+        streamInfoResult.setStream(stream);
+        streamInfoResult.setApp(app);
+        if (addr == null) {
+            addr = mediaServer.getStreamIp();
+        }
+
+        streamInfoResult.setIp(addr);
+        streamInfoResult.setMediaServerId(mediaServer.getId());
+        String callIdParam = ObjectUtils.isEmpty(callId)?"":"?callId=" + callId;
+        streamInfoResult.setRtmp(addr, mediaServer.getRtmpPort(),mediaServer.getRtmpSSlPort(), app,  stream, callIdParam);
+        streamInfoResult.setRtsp(addr, mediaServer.getRtspPort(),mediaServer.getRtspSSLPort(), app,  stream, callIdParam);
+
+
+        if ("abl".equals(mediaServer.getType())) {
+            String flvFile = String.format("%s/%s.flv%s", app, stream, callIdParam);
+            streamInfoResult.setFlv(addr, mediaServer.getFlvPort(),mediaServer.getFlvSSLPort(), flvFile);
+            streamInfoResult.setWsFlv(addr, mediaServer.getWsFlvPort(),mediaServer.getWsFlvSSLPort(), flvFile);
+        }else {
+            String flvFile = String.format("%s/%s.live.flv%s", app, stream, callIdParam);
+            streamInfoResult.setFlv(addr, mediaServer.getFlvPort(),mediaServer.getFlvSSLPort(), flvFile);
+            streamInfoResult.setWsFlv(addr, mediaServer.getWsFlvPort(),mediaServer.getWsFlvSSLPort(), flvFile);
+        }
+
+        streamInfoResult.setFmp4(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app,  stream, callIdParam);
+        streamInfoResult.setHls(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app,  stream, callIdParam);
+        streamInfoResult.setTs(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app,  stream, callIdParam);
+        streamInfoResult.setRtc(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app,  stream, callIdParam, isPlay);
+
+        streamInfoResult.setMediaInfo(mediaInfo);
+        return streamInfoResult;
+    }
+
+    @Override
+    public Boolean isStreamReady(MediaServer mediaServer, String rtp, String streamId) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[isStreamReady] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            return false;
+        }
+        MediaInfo mediaInfo = mediaNodeServerService.getMediaInfo(mediaServer, rtp, streamId);
+        return mediaInfo != null;
+    }
+
+    @Override
+    public void startSendRtpPassive(MediaServer mediaServer, ParentPlatform platform, SendRtpItem sendRtpItem, Integer timeout) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[startSendRtpPassive] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒癿ediaServer瀵瑰簲鐨勫疄鐜扮被");
+        }
+        mediaNodeServerService.startSendRtpPassive(mediaServer, sendRtpItem, timeout);
+        sendPlatformStartPlayMsg(platform, sendRtpItem);
+    }
+
+    @Override
+    public void startSendRtpStream(MediaServer mediaServer, ParentPlatform platform, SendRtpItem sendRtpItem) {
+        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
+        if (mediaNodeServerService == null) {
+            logger.info("[startSendRtpStream] 澶辫触, mediaServer鐨勭被鍨嬶細 {}锛屾湭鎵惧埌瀵瑰簲鐨勫疄鐜扮被", mediaServer.getType());
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒癿ediaServer瀵瑰簲鐨勫疄鐜扮被");
+        }
+        logger.info("[寮�濮嬫帹娴乚 rtp/{}, 鐩爣={}:{}锛孲SRC={}, RTCP={}", sendRtpItem.getStream(),
+                sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
+        mediaNodeServerService.startSendRtpStream(mediaServer, sendRtpItem);
+        sendPlatformStartPlayMsg(platform, sendRtpItem);
+
+    }
+
+    private void sendPlatformStartPlayMsg(ParentPlatform platform, SendRtpItem sendRtpItem) {
+        if (sendRtpItem.getPlayType() == InviteStreamType.PUSH && platform  != null) {
+            MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, sendRtpItem.getApp(), sendRtpItem.getStream(),
+                    sendRtpItem.getChannelId(), platform.getServerGBId(), platform.getName(), userSetting.getServerId(),
+                    sendRtpItem.getMediaServerId());
+            messageForPushChannel.setPlatFormIndex(platform.getId());
+            redisCatchStorage.sendPlatformStartPlayMsg(messageForPushChannel);
+        }
+    }
+}
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 5735f37..6f6d5ea 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
@@ -2,7 +2,7 @@
 
 import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.utils.SSLSocketClientUtil;
 import okhttp3.*;
 import okhttp3.logging.HttpLoggingInterceptor;
@@ -70,7 +70,7 @@
     }
 
 
-    public JSONObject sendGet(MediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
+    public JSONObject sendGet(MediaServer mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
         OkHttpClient client = getClient();
 
         if (mediaServerItem == null) {
@@ -155,7 +155,7 @@
         return responseJSON;
     }
 
-    public JSONObject sendPost(MediaServerItem mediaServerItem, String url,
+    public JSONObject sendPost(MediaServer mediaServerItem, String url,
                                JSONObject param, ZLMRESTfulUtils.RequestCallback callback,
                                Integer readTimeOut) {
         OkHttpClient client = getClient(readTimeOut);
@@ -244,12 +244,12 @@
         return responseJSON;
     }
 
-    public JSONObject getInfo(MediaServerItem mediaServerItem, RequestCallback callback){
+    public JSONObject getInfo(MediaServer mediaServerItem, RequestCallback callback){
         Map<String, Object> param = new HashMap<>();
         return sendGet(mediaServerItem, "api/record/info",param, callback);
     }
 
-    public JSONObject addTask(MediaServerItem mediaServerItem, String app, String stream, String startTime,
+    public JSONObject addTask(MediaServer mediaServerItem, String app, String stream, String startTime,
                               String endTime, String callId, List<String> filePathList, String remoteHost) {
 
         JSONObject videoTaskInfoJSON = new JSONObject();
@@ -266,7 +266,7 @@
         return sendPost(mediaServerItem, urlStr, videoTaskInfoJSON, null, 30);
     }
 
-    public JSONObject queryTaskList(MediaServerItem mediaServerItem, String app, String stream, String callId,
+    public JSONObject queryTaskList(MediaServer mediaServerItem, String app, String stream, String callId,
                                     String taskId, Boolean isEnd, String scheme) {
         Map<String, Object> param = new HashMap<>();
         if (!ObjectUtils.isEmpty(app)) {
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java
index 3f28d02..7fffc10 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java
@@ -3,7 +3,7 @@
 import com.genersoft.iot.vmp.common.VideoManagerConstants;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
 import org.apache.commons.lang3.math.NumberUtils;
 import org.slf4j.Logger;
@@ -30,7 +30,7 @@
 
     private final String KEY = "VM_MEDIA_SEND_RTP_PORT_";
 
-    public synchronized int getNextPort(MediaServerItem mediaServer) {
+    public synchronized int getNextPort(MediaServer mediaServer) {
         if (mediaServer == null) {
             logger.warn("[鍙戦�佺鍙g鐞哴 鍙傛暟閿欒锛宮ediaServer涓篘ULL");
             return -1;
@@ -83,6 +83,7 @@
     }
 
     private synchronized int getSendPort(int startPort, int endPort, String sendIndexKey, Map<Integer, SendRtpItem> sendRtpItemMap){
+        // TODO 杩欓噷鏀逛负鍙彇鍋舵暟绔彛
         RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(sendIndexKey , redisTemplate.getConnectionFactory());
         if (redisAtomicInteger.get() < startPort) {
             redisAtomicInteger.set(startPort);
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 6076db4..f5b1b6c 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -2,55 +2,40 @@
 
 import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.common.InviteInfo;
-import com.genersoft.iot.vmp.common.InviteSessionType;
-import com.genersoft.iot.vmp.common.StreamInfo;
-import com.genersoft.iot.vmp.common.VideoManagerConstants;
 import com.genersoft.iot.vmp.conf.UserSetting;
-import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
-import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
-import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
 import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
-import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
-import com.genersoft.iot.vmp.media.zlm.dto.HookType;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
-import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
+import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.event.media.*;
+import com.genersoft.iot.vmp.media.event.mediaServer.MediaSendRtpStoppedEvent;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.ZLMServerConfig;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.*;
+import com.genersoft.iot.vmp.media.zlm.event.HookZlmServerKeepaliveEvent;
+import com.genersoft.iot.vmp.media.zlm.event.HookZlmServerStartEvent;
 import com.genersoft.iot.vmp.service.*;
-import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
-import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
-import com.genersoft.iot.vmp.utils.DateUtil;
-import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
-import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
-import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
-import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.*;
-import org.springframework.web.context.request.async.DeferredResult;
 
 import javax.servlet.http.HttpServletRequest;
-import javax.sip.InvalidArgumentException;
-import javax.sip.SipException;
-import java.text.ParseException;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.UUID;
 
 /**
  * @description:閽堝 ZLMediaServer鐨刪ook浜嬩欢鐩戝惉
@@ -106,7 +91,7 @@
     private ZLMMediaListManager zlmMediaListManager;
 
     @Autowired
-    private ZlmHttpHookSubscribe subscribe;
+    private HookSubscribe subscribe;
 
     @Autowired
     private UserSetting userSetting;
@@ -130,25 +115,25 @@
     @Autowired
     private RedisTemplate<Object, Object> redisTemplate;
 
+    @Autowired
+    private ApplicationEventPublisher applicationEventPublisher;
+
     /**
      * 鏈嶅姟鍣ㄥ畾鏃朵笂鎶ユ椂闂达紝涓婃姤闂撮殧鍙厤缃紝榛樿10s涓婃姤涓�娆�
      */
     @ResponseBody
-
     @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8")
     public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) {
-
-
-        taskExecutor.execute(() -> {
-            List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
-            if (subscribes != null && !subscribes.isEmpty()) {
-                for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
-                    subscribe.response(null, param);
-                }
+        try {
+            HookZlmServerKeepaliveEvent event = new HookZlmServerKeepaliveEvent(this);
+            MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
+            if (mediaServerItem != null) {
+                event.setMediaServerItem(mediaServerItem);
+                applicationEventPublisher.publishEvent(event);
             }
-        });
-        mediaServerService.updateMediaServerKeepalive(param.getMediaServerId(), param.getData());
-
+        }catch (Exception e) {
+            logger.info("[ZLM-HOOK-蹇冭烦] 鍙戦�侀�氱煡澶辫触 ", e);
+        }
         return HookResult.SUCCESS();
     }
 
@@ -156,32 +141,17 @@
      * 鎾斁鍣ㄩ壌鏉冧簨浠讹紝rtsp/rtmp/http-flv/ws-flv/hls鐨勬挱鏀鹃兘灏嗚Е鍙戞閴存潈浜嬩欢銆�
      */
     @ResponseBody
-
     @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
     public HookResult onPlay(@RequestBody OnPlayHookParam param) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("[ZLM HOOK] 鎾斁閴存潈锛歿}->{}", param.getMediaServerId(), param);
-        }
-        String mediaServerId = param.getMediaServerId();
 
-        taskExecutor.execute(() -> {
-            JSONObject json = (JSONObject) JSON.toJSON(param);
-            ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json);
-            if (subscribe != null) {
-                MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
-                if (mediaInfo != null) {
-                    subscribe.response(mediaInfo, param);
-                }
-            }
-        });
-        if (!"rtp".equals(param.getApp())) {
-            Map<String, String> paramMap = urlParamToMap(param.getParams());
-            StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
-            if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) {
-                return new HookResult(401, "Unauthorized");
-            }
+        Map<String, String> paramMap = urlParamToMap(param.getParams());
+        // 瀵逛簬鎾斁娴佽繘琛岄壌鏉�
+        boolean authenticateResult = mediaService.authenticatePlay(param.getApp(), param.getStream(), paramMap.get("callId"));
+        if (!authenticateResult) {
+            logger.info("[ZLM HOOK] 鎾斁閴存潈 澶辫触锛歿}->{}", param.getMediaServerId(), param);
+            return new HookResult(401, "Unauthorized");
         }
-
+        logger.info("[ZLM HOOK] 鎾斁閴存潈鎴愬姛锛歿}->{}", param.getMediaServerId(), param);
         return HookResult.SUCCESS();
     }
 
@@ -195,136 +165,24 @@
         JSONObject json = (JSONObject) JSON.toJSON(param);
 
         logger.info("[ZLM HOOK]鎺ㄦ祦閴存潈锛歿}->{}", param.getMediaServerId(), param);
+        // TODO 鍔犲揩澶勭悊閫熷害
 
         String mediaServerId = json.getString("mediaServerId");
-        MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
-        if (mediaInfo == null) {
-            return new HookResultForOnPublish(200, "success");
-        }
-        // 鎺ㄦ祦閴存潈鐨勫鐞�
-        if (!"rtp".equals(param.getApp())) {
-            StreamProxyItem stream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
-            if (stream != null) {
-                HookResultForOnPublish result = HookResultForOnPublish.SUCCESS();
-                result.setEnable_audio(stream.isEnableAudio());
-                result.setEnable_mp4(stream.isEnableMp4());
-                return result;
-            }
-            if (userSetting.getPushAuthority()) {
-                // 鎺ㄦ祦閴存潈
-                if (param.getParams() == null) {
-                    logger.info("鎺ㄦ祦閴存潈澶辫触锛� 缂哄皯蹇呰鍙傛暟锛歴ign=md5(user琛ㄧ殑pushKey)");
-                    return new HookResultForOnPublish(401, "Unauthorized");
-                }
-                Map<String, String> paramMap = urlParamToMap(param.getParams());
-                String sign = paramMap.get("sign");
-                if (sign == null) {
-                    logger.info("鎺ㄦ祦閴存潈澶辫触锛� 缂哄皯蹇呰鍙傛暟锛歴ign=md5(user琛ㄧ殑pushKey)");
-                    return new HookResultForOnPublish(401, "Unauthorized");
-                }
-                // 鎺ㄦ祦鑷畾涔夋挱鏀鹃壌鏉冪爜
-                String callId = paramMap.get("callId");
-                // 閴存潈閰嶇疆
-                boolean hasAuthority = userService.checkPushAuthority(callId, sign);
-                if (!hasAuthority) {
-                    logger.info("鎺ㄦ祦閴存潈澶辫触锛� sign 鏃犳潈闄�: callId={}. sign={}", callId, sign);
-                    return new HookResultForOnPublish(401, "Unauthorized");
-                }
-                StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
-                streamAuthorityInfo.setCallId(callId);
-                streamAuthorityInfo.setSign(sign);
-                // 閴存潈閫氳繃
-                redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
-            }
-        } else {
-            zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId());
+        MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
+        if (mediaServer == null) {
+            return new HookResultForOnPublish(0, "success");
         }
 
-
-        HookResultForOnPublish result = HookResultForOnPublish.SUCCESS();
-        result.setEnable_audio(true);
-        taskExecutor.execute(() -> {
-            ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);
-            if (subscribe != null) {
-                subscribe.response(mediaInfo, param);
-            }
-        });
-
-        // 鏄惁褰曞儚
-        if ("rtp".equals(param.getApp())) {
-            result.setEnable_mp4(userSetting.getRecordSip());
-        } else {
-            result.setEnable_mp4(userSetting.isRecordPushLive());
+        ResultForOnPublish resultForOnPublish = mediaService.authenticatePublish(mediaServer, param.getApp(), param.getStream(), param.getParams());
+        if (resultForOnPublish != null) {
+            HookResultForOnPublish successResult = HookResultForOnPublish.getInstance(resultForOnPublish);
+            logger.info("[ZLM HOOK]鎺ㄦ祦閴存潈 鍝嶅簲锛歿}->{}->>>>{}", param.getMediaServerId(), param, successResult);
+            return successResult;
+        }else {
+            HookResultForOnPublish fail = HookResultForOnPublish.Fail();
+            logger.info("[ZLM HOOK]鎺ㄦ祦閴存潈 鍝嶅簲锛歿}->{}->>>>{}", param.getMediaServerId(), param, fail);
+            return fail;
         }
-        // 鍥芥爣娴�
-        if ("rtp".equals(param.getApp())) {
-
-            InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
-
-            // 鍗曠鍙fā寮忎笅淇敼娴� ID
-            if (!mediaInfo.isRtpEnable() && inviteInfo == null) {
-                String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));
-                inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc);
-                if (inviteInfo != null) {
-                    result.setStream_replace(inviteInfo.getStream());
-                    logger.info("[ZLM HOOK]鎺ㄦ祦閴存潈 stream: {} 鏇挎崲涓� {}", param.getStream(), inviteInfo.getStream());
-                }
-            }
-
-            // 璁剧疆闊抽淇℃伅鍙婂綍鍒朵俊鎭�
-            List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream());
-            if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) {
-
-                // 涓哄綍鍒跺浗鏍囨ā鎷熶竴涓壌鏉冧俊鎭�, 鏂逛究鍚庣画鍐欏叆褰曞儚鏂囦欢鏃朵娇鐢�
-                StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
-                streamAuthorityInfo.setApp(param.getApp());
-                streamAuthorityInfo.setStream(ssrcTransactionForAll.get(0).getStream());
-                streamAuthorityInfo.setCallId(ssrcTransactionForAll.get(0).getSipTransactionInfo().getCallId());
-
-                redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), ssrcTransactionForAll.get(0).getStream(), streamAuthorityInfo);
-
-                String deviceId = ssrcTransactionForAll.get(0).getDeviceId();
-                String channelId = ssrcTransactionForAll.get(0).getChannelId();
-                DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
-                if (deviceChannel != null) {
-                    result.setEnable_audio(deviceChannel.isHasAudio());
-                }
-                // 濡傛灉鏄綍鍍忎笅杞藉氨璁剧疆瑙嗛闂撮殧鍗佺
-                if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) {
-                    // 鑾峰彇褰曞儚鐨勬�绘椂闀匡紝鐒跺悗璁剧疆涓鸿繖涓棰戠殑鏃堕暱
-                    InviteInfo inviteInfoForDownload = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, param.getStream());
-                    if (inviteInfoForDownload != null && inviteInfoForDownload.getStreamInfo() != null) {
-                        String startTime = inviteInfoForDownload.getStreamInfo().getStartTime();
-                        String endTime = inviteInfoForDownload.getStreamInfo().getEndTime();
-                        long difference = DateUtil.getDifference(startTime, endTime) / 1000;
-                        result.setMp4_max_second((int) difference);
-                        result.setEnable_mp4(true);
-                        // 璁剧疆涓�2淇濊瘉寰楀埌鐨刴p4鐨勬椂闀挎槸姝e父鐨�
-                        result.setModify_stamp(2);
-                    }
-                }
-                // 濡傛灉鏄痶alk瀵硅锛屽垯榛樿鑾峰彇澹伴煶
-                if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.TALK) {
-                    result.setEnable_audio(true);
-                }
-            }
-        } else if (param.getApp().equals("broadcast")) {
-            result.setEnable_audio(true);
-        } else if (param.getApp().equals("talk")) {
-            result.setEnable_audio(true);
-        }
-        if (param.getApp().equalsIgnoreCase("rtp")) {
-            String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + param.getStream();
-            OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo) redisTemplate.opsForValue().get(receiveKey);
-
-            String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + param.getStream();
-            OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo) redisTemplate.opsForValue().get(receiveKeyForPS);
-            if (otherRtpSendInfo != null || otherPsSendInfo != null) {
-                result.setEnable_mp4(true);
-            }
-        }
-        logger.info("[ZLM HOOK]鎺ㄦ祦閴存潈 鍝嶅簲锛歿}->{}->>>>{}", param.getMediaServerId(), param, result);
-        return result;
     }
 
 
@@ -335,226 +193,20 @@
     @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8")
     public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) {
 
-        if (param.isRegist()) {
-            logger.info("[ZLM HOOK] 娴佹敞鍐�, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
-        } else {
-            logger.info("[ZLM HOOK] 娴佹敞閿�, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
+        MediaServer mediaServer = mediaServerService.getOne(param.getMediaServerId());
+        if (mediaServer == null) {
+            return HookResult.SUCCESS();
         }
 
-        JSONObject json = (JSONObject) JSON.toJSON(param);
-        taskExecutor.execute(() -> {
-            ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);
-            MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
-            if (mediaInfo == null) {
-                logger.info("[ZLM HOOK] 娴佸彉鍖栨湭鎵惧埌ZLM, {}", param.getMediaServerId());
-                return;
-            }
-            if (subscribe != null) {
-                subscribe.response(mediaInfo, param);
-            }
-
-            List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
-            // TODO 閲嶆瀯姝ゅ閫昏緫
-            if (param.isRegist()) {
-                // 澶勭悊娴佹敞鍐岀殑閴存潈淇℃伅锛� 娴佹敞閿�杩欓噷涓嶅啀鍒犻櫎閴存潈淇℃伅锛屼笅娆℃潵浜嗘柊鐨勯壌鏉冧俊鎭細瀵瑰氨鐨勮繘琛岃鐩�
-                if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
-                        || param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
-                        || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
-                    StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
-                    if (streamAuthorityInfo == null) {
-                        streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
-                    } else {
-                        streamAuthorityInfo.setOriginType(param.getOriginType());
-                        streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr());
-                    }
-                    redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
-                }
-            }
-            if ("rtsp".equals(param.getSchema())) {
-                logger.info("娴佸彉鍖栵細娉ㄥ唽->{}, app->{}, stream->{}", param.isRegist(), param.getApp(), param.getStream());
-                if (param.isRegist()) {
-                    mediaServerService.addCount(param.getMediaServerId());
-                } else {
-                    mediaServerService.removeCount(param.getMediaServerId());
-                }
-
-                int updateStatusResult = streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream());
-                if (updateStatusResult > 0) {
-
-                }
-
-                if ("rtp".equals(param.getApp()) && !param.isRegist()) {
-                    InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
-                    if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) {
-                        inviteStreamService.removeInviteInfo(inviteInfo);
-                        storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
-                    }
-                } else if ("broadcast".equals(param.getApp())) {
-                    // 璇煶瀵硅鎺ㄦ祦  stream闇�瑕佹弧瓒虫牸寮廳eviceId_channelId
-                    if (param.getStream().indexOf("_") > 0) {
-                        String[] streamArray = param.getStream().split("_");
-                        if (streamArray.length == 2) {
-                            String deviceId = streamArray[0];
-                            String channelId = streamArray[1];
-                            Device device = deviceService.getDevice(deviceId);
-                            if (device != null) {
-                                if (param.isRegist()) {
-                                    if (audioBroadcastManager.exit(deviceId, channelId)) {
-                                        playService.stopAudioBroadcast(deviceId, channelId);
-                                    }
-                                    // 寮�鍚闊冲璁查�氶亾
-                                    try {
-                                        playService.audioBroadcastCmd(device, channelId, mediaInfo, param.getApp(), param.getStream(), 60, false, (msg) -> {
-                                            logger.info("[璇煶瀵硅] 閫氶亾寤虹珛鎴愬姛, device: {}, channel: {}", deviceId, channelId);
-                                        });
-                                    } catch (InvalidArgumentException | ParseException | SipException e) {
-                                        logger.error("[鍛戒护鍙戦�佸け璐 璇煶瀵硅: {}", e.getMessage());
-                                    }
-                                } else {
-                                    // 娴佹敞閿�
-                                    playService.stopAudioBroadcast(deviceId, channelId);
-                                }
-                            } else {
-                                logger.info("[璇煶瀵硅] 鏈壘鍒拌澶囷細{}", deviceId);
-                            }
-                        }
-                    }
-                } else if ("talk".equals(param.getApp())) {
-                    // 璇煶瀵硅鎺ㄦ祦  stream闇�瑕佹弧瓒虫牸寮廳eviceId_channelId
-                    if (param.getStream().indexOf("_") > 0) {
-                        String[] streamArray = param.getStream().split("_");
-                        if (streamArray.length == 2) {
-                            String deviceId = streamArray[0];
-                            String channelId = streamArray[1];
-                            Device device = deviceService.getDevice(deviceId);
-                            if (device != null) {
-                                if (param.isRegist()) {
-                                    if (audioBroadcastManager.exit(deviceId, channelId)) {
-                                        playService.stopAudioBroadcast(deviceId, channelId);
-                                    }
-                                    // 寮�鍚闊冲璁查�氶亾
-                                    playService.talkCmd(device, channelId, mediaInfo, param.getStream(), (msg) -> {
-                                        logger.info("[璇煶瀵硅] 閫氶亾寤虹珛鎴愬姛, device: {}, channel: {}", deviceId, channelId);
-                                    });
-                                } else {
-                                    // 娴佹敞閿�
-                                    playService.stopTalk(device, channelId, param.isRegist());
-                                }
-                            } else {
-                                logger.info("[璇煶瀵硅] 鏈壘鍒拌澶囷細{}", deviceId);
-                            }
-                        }
-                    }
-
-                } else {
-                    if (!"rtp".equals(param.getApp())) {
-                        String type = OriginType.values()[param.getOriginType()].getType();
-                        if (param.isRegist()) {
-                            StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(
-                                    param.getApp(), param.getStream());
-                            String callId = null;
-                            if (streamAuthorityInfo != null) {
-                                callId = streamAuthorityInfo.getCallId();
-                            }
-                            StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo,
-                                    param.getApp(), param.getStream(), tracks, callId);
-                            param.setStreamInfo(new StreamContent(streamInfoByAppAndStream));
-                            redisCatchStorage.addStream(mediaInfo, type, param.getApp(), param.getStream(), param);
-                            if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
-                                    || param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
-                                    || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
-                                param.setSeverId(userSetting.getServerId());
-                                zlmMediaListManager.addPush(param);
-
-                                // 鍐椾綑鏁版嵁锛岃嚜宸辩郴缁熶腑鑷敤
-                                redisCatchStorage.addPushListItem(param.getApp(), param.getStream(), param);
-                            }
-                        } else {
-                            // 鍏煎娴佹敞閿�鏃剁被鍨嬩粠redis璁板綍鑾峰彇
-                            OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo(
-                                    param.getApp(), param.getStream(), param.getMediaServerId());
-                            if (onStreamChangedHookParam != null) {
-                                type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType();
-                                redisCatchStorage.removeStream(mediaInfo.getId(), type, param.getApp(), param.getStream());
-                                if ("PUSH".equalsIgnoreCase(type)) {
-                                    // 鍐椾綑鏁版嵁锛岃嚜宸辩郴缁熶腑鑷敤
-                                    redisCatchStorage.removePushListItem(param.getApp(), param.getStream(), param.getMediaServerId());
-                                }
-                            }
-                            GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());
-                            if (gbStream != null) {
-//									eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
-                            }
-                            zlmMediaListManager.removeMedia(param.getApp(), param.getStream());
-                        }
-                        GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());
-                        if (gbStream != null) {
-                            if (userSetting.isUsePushingAsStatus()) {
-                                eventPublisher.catalogEventPublishForStream(null, gbStream, param.isRegist() ? CatalogEvent.ON : CatalogEvent.OFF);
-                            }
-                        }
-                        if (type != null) {
-                            // 鍙戦�佹祦鍙樺寲redis娑堟伅
-                            JSONObject jsonObject = new JSONObject();
-                            jsonObject.put("serverId", userSetting.getServerId());
-                            jsonObject.put("app", param.getApp());
-                            jsonObject.put("stream", param.getStream());
-                            jsonObject.put("register", param.isRegist());
-                            jsonObject.put("mediaServerId", param.getMediaServerId());
-                            redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
-                        }
-                    }
-                }
-                if (!param.isRegist()) {
-                    List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());
-                    if (!sendRtpItems.isEmpty()) {
-                        for (SendRtpItem sendRtpItem : sendRtpItems) {
-                            if (sendRtpItem == null) {
-                                continue;
-                            }
-
-                            if (sendRtpItem.getApp().equals(param.getApp())) {
-                                logger.info(sendRtpItem.toString());
-                                if (userSetting.getServerId().equals(sendRtpItem.getServerId())) {
-                                    MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
-                                            sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(),
-                                            sendRtpItem.getPlatformId(), null, userSetting.getServerId(), param.getMediaServerId());
-                                    // 閫氱煡鍏朵粬wvp鍋滄鍙戞祦
-                                    redisCatchStorage.sendPushStreamClose(messageForPushChannel);
-                                }else {
-                                    String platformId = sendRtpItem.getPlatformId();
-                                    ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
-                                    Device device = deviceService.getDevice(platformId);
-
-                                    try {
-                                        if (platform != null) {
-                                            commanderFroPlatform.streamByeCmd(platform, sendRtpItem);
-                                            redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(),
-                                                    sendRtpItem.getCallId(), sendRtpItem.getStream());
-                                        } else {
-                                            cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId());
-                                            if (sendRtpItem.getPlayType().equals(InviteStreamType.BROADCAST)
-                                                    || sendRtpItem.getPlayType().equals(InviteStreamType.TALK)) {
-                                                AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
-                                                if (audioBroadcastCatch != null) {
-                                                    // 鏉ヨ嚜涓婄骇骞冲彴鐨勫仠姝㈠璁�
-                                                    logger.info("[鍋滄瀵硅] 鏉ヨ嚜涓婄骇锛屽钩鍙帮細{}, 閫氶亾锛歿}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
-                                                    audioBroadcastManager.del(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
-                                                }
-                                            }
-                                        }
-                                    } catch (SipException | InvalidArgumentException | ParseException |
-                                             SsrcTransactionNotFoundException e) {
-                                        logger.error("[鍛戒护鍙戦�佸け璐 鍙戦�丅YE: {}", e.getMessage());
-                                    }
-                                }
-
-                            }
-                        }
-                    }
-                }
-            }
-        });
+        if (param.isRegist()) {
+            logger.info("[ZLM HOOK] 娴佹敞鍐�, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
+            MediaArrivalEvent mediaArrivalEvent = MediaArrivalEvent.getInstance(this, param, mediaServer);
+            applicationEventPublisher.publishEvent(mediaArrivalEvent);
+        } else {
+            logger.info("[ZLM HOOK] 娴佹敞閿�, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
+            MediaDepartureEvent mediaDepartureEvent = MediaDepartureEvent.getInstance(this, param, mediaServer);
+            applicationEventPublisher.publishEvent(mediaDepartureEvent);
+        }
         return HookResult.SUCCESS();
     }
 
@@ -568,104 +220,9 @@
         logger.info("[ZLM HOOK]娴佹棤浜鸿鐪嬶細{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(),
                 param.getApp(), param.getStream());
         JSONObject ret = new JSONObject();
-        ret.put("code", 0);
-        // 鍥芥爣绫诲瀷鐨勬祦
-        if ("rtp".equals(param.getApp())) {
-            ret.put("close", userSetting.getStreamOnDemand());
-            // 鍥芥爣娴侊紝 鐐规挱/褰曞儚鍥炴斁/褰曞儚涓嬭浇
-            InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
-            // 鐐规挱
-            if (inviteInfo != null) {
-                // 褰曞儚涓嬭浇
-                if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) {
-                    ret.put("close", false);
-                    return ret;
-                }
-                // 鏀跺埌鏃犱汉瑙傜湅璇存槑娴佷篃娌℃湁鍦ㄥ線涓婄骇鎺ㄩ��
-                if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) {
-                    List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChannelId(
-                            inviteInfo.getChannelId());
-                    if (!sendRtpItems.isEmpty()) {
-                        for (SendRtpItem sendRtpItem : sendRtpItems) {
-                            ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
-                            try {
-                                commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
-                            } catch (SipException | InvalidArgumentException | ParseException e) {
-                                logger.error("[鍛戒护鍙戦�佸け璐 鍥芥爣绾ц仈 鍙戦�丅YE: {}", e.getMessage());
-                            }
-                            redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
-                                    sendRtpItem.getCallId(), sendRtpItem.getStream());
-                            if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) {
-                                MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
-                                        sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(),
-                                        sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId());
-                                messageForPushChannel.setPlatFormIndex(parentPlatform.getId());
-                                redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel);
-                            }
-                        }
-                    }
-                }
-                Device device = deviceService.getDevice(inviteInfo.getDeviceId());
-                if (device != null) {
-                    try {
-                        // 澶氭煡璇竴娆¢槻姝㈠凡缁忚澶勭悊浜�
-                        InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(),
-                                inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
-                        if (info != null) {
-                            cmder.streamByeCmd(device, inviteInfo.getChannelId(),
-                                    inviteInfo.getStream(), null);
-                        } else {
-                            logger.info("[鏃犱汉瑙傜湅] 鏈壘鍒拌澶囩殑鐐规挱淇℃伅锛� {}锛� 娴侊細{}", inviteInfo.getDeviceId(), param.getStream());
-                        }
-                    } catch (InvalidArgumentException | ParseException | SipException |
-                             SsrcTransactionNotFoundException e) {
-                        logger.error("[鏃犱汉瑙傜湅]鐐规挱锛� 鍙戦�丅YE澶辫触 {}", e.getMessage());
-                    }
-                } else {
-                    logger.info("[鏃犱汉瑙傜湅] 鏈壘鍒拌澶囷細 {}锛屾祦锛歿}", inviteInfo.getDeviceId(), param.getStream());
-                }
 
-                inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(),
-                        inviteInfo.getChannelId(), inviteInfo.getStream());
-                storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
-                return ret;
-            }
-            SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, param.getStream(), null);
-            if (sendRtpItem != null && "talk".equals(sendRtpItem.getApp())) {
-                ret.put("close", false);
-                return ret;
-            }
-        } else if ("talk".equals(param.getApp()) || "broadcast".equals(param.getApp())) {
-            ret.put("close", false);
-        } else {
-            // 闈炲浗鏍囨祦 鎺ㄦ祦/鎷夋祦浠g悊
-            // 鎷夋祦浠g悊
-            StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
-            if (streamProxyItem != null) {
-                if (streamProxyItem.isEnableRemoveNoneReader()) {
-                    // 鏃犱汉瑙傜湅鑷姩绉婚櫎
-                    ret.put("close", true);
-                    streamProxyService.del(param.getApp(), param.getStream());
-                    String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl();
-                    logger.info("[{}/{}]<-[{}] 鎷夋祦浠g悊鏃犱汉瑙傜湅宸茬粡绉婚櫎", param.getApp(), param.getStream(), url);
-                } else if (streamProxyItem.isEnableDisableNoneReader()) {
-                    // 鏃犱汉瑙傜湅鍋滅敤
-                    ret.put("close", true);
-                    // 淇敼鏁版嵁
-                    streamProxyService.stop(param.getApp(), param.getStream());
-                } else {
-                    // 鏃犱汉瑙傜湅涓嶅仛澶勭悊
-                    ret.put("close", false);
-                }
-                return ret;
-            }
-            // TODO 鎺ㄦ祦鍏锋湁涓诲姩鎬э紝鏆傛椂涓嶅仛澶勭悊
-//			StreamPushItem streamPushItem = streamPushService.getPush(app, streamId);
-//			if (streamPushItem != null) {
-//				// TODO 鍙戦�佸仠姝�
-//
-//			}
-        }
+        boolean close = mediaService.closeStreamOnNoneReader(param.getMediaServerId(), param.getApp(), param.getStream(), param.getSchema());
+        ret.put("code", close);
         return ret;
     }
 
@@ -674,119 +231,17 @@
      */
     @ResponseBody
     @PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8")
-    public DeferredResult<HookResult> onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) {
+    public HookResult onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) {
         logger.info("[ZLM HOOK] 娴佹湭鎵惧埌锛歿}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
 
-        DeferredResult<HookResult> defaultResult = new DeferredResult<>();
 
-        MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
-        if (!userSetting.isAutoApplyPlay() || mediaInfo == null) {
-            defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));
-            return defaultResult;
+        MediaServer mediaServer = mediaServerService.getOne(param.getMediaServerId());
+        if (!userSetting.isAutoApplyPlay() || mediaServer == null) {
+            return HookResult.SUCCESS();
         }
-
-        if ("rtp".equals(param.getApp())) {
-            String[] s = param.getStream().split("_");
-            if ((s.length != 2 && s.length != 4)) {
-                defaultResult.setResult(HookResult.SUCCESS());
-                return defaultResult;
-            }
-            String deviceId = s[0];
-            String channelId = s[1];
-            Device device = redisCatchStorage.getDevice(deviceId);
-            if (device == null || !device.isOnLine()) {
-                defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));
-                return defaultResult;
-            }
-            DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
-            if (deviceChannel == null) {
-                defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));
-                return defaultResult;
-            }
-            if (s.length == 2) {
-                logger.info("[ZLM HOOK] 棰勮娴佹湭鎵惧埌, 鍙戣捣鑷姩鐐规挱锛歿}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
-
-                RequestMessage msg = new RequestMessage();
-                String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
-                boolean exist = resultHolder.exist(key, null);
-                msg.setKey(key);
-                String uuid = UUID.randomUUID().toString();
-                msg.setId(uuid);
-                DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
-
-                result.onTimeout(() -> {
-                    logger.info("[ZLM HOOK] 棰勮娴佽嚜鍔ㄧ偣鎾�, 绛夊緟瓒呮椂");
-                    msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "鐐规挱瓒呮椂"));
-                    resultHolder.invokeAllResult(msg);
-                    inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
-                    storager.stopPlay(deviceId, channelId);
-                });
-
-                resultHolder.put(key, uuid, result);
-
-                if (!exist) {
-                    playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> {
-                        msg.setData(new HookResult(code, message));
-                        resultHolder.invokeResult(msg);
-                    });
-                }
-                return result;
-            } else if (s.length == 4) {
-                // 姝ゆ椂涓哄綍鍍忓洖鏀撅紝 褰曞儚鍥炴斁鏍煎紡涓�> 璁惧ID_閫氶亾ID_寮�濮嬫椂闂確缁撴潫鏃堕棿
-                String startTimeStr = s[2];
-                String endTimeStr = s[3];
-                if (startTimeStr == null || endTimeStr == null || startTimeStr.length() != 14 || endTimeStr.length() != 14) {
-                    defaultResult.setResult(HookResult.SUCCESS());
-                    return defaultResult;
-                }
-                String startTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(startTimeStr);
-                String endTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(endTimeStr);
-                logger.info("[ZLM HOOK] 鍥炴斁娴佹湭鎵惧埌, 鍙戣捣鑷姩鐐规挱锛歿}->{}->{}/{}-{}-{}",
-                        param.getMediaServerId(), param.getSchema(),
-                        param.getApp(), param.getStream(),
-                        startTime, endTime
-                );
-                RequestMessage msg = new RequestMessage();
-                String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
-                boolean exist = resultHolder.exist(key, null);
-                msg.setKey(key);
-                String uuid = UUID.randomUUID().toString();
-                msg.setId(uuid);
-                DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
-
-                result.onTimeout(() -> {
-                    logger.info("[ZLM HOOK] 鍥炴斁娴佽嚜鍔ㄧ偣鎾�, 绛夊緟瓒呮椂");
-                    // 閲婃斁rtpserver
-                    msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "鐐规挱瓒呮椂"));
-                    resultHolder.invokeResult(msg);
-                });
-
-                resultHolder.put(key, uuid, result);
-
-                if (!exist) {
-                    SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaInfo, param.getStream(), null,
-                            device.isSsrcCheck(), true, 0, false, false, device.getStreamModeForParam());
-                    playService.playBack(mediaInfo, ssrcInfo, deviceId, channelId, startTime, endTime, (code, message, data) -> {
-                        msg.setData(new HookResult(code, message));
-                        resultHolder.invokeResult(msg);
-                    });
-                }
-                return result;
-            } else {
-                defaultResult.setResult(HookResult.SUCCESS());
-                return defaultResult;
-            }
-
-        } else {
-            // 鎷夋祦浠g悊
-            StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
-            if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) {
-                streamProxyService.start(param.getApp(), param.getStream());
-            }
-            DeferredResult<HookResult> result = new DeferredResult<>();
-            result.setResult(HookResult.SUCCESS());
-            return result;
-        }
+        MediaNotFoundEvent mediaNotFoundEvent = MediaNotFoundEvent.getInstance(this, param, mediaServer);
+        applicationEventPublisher.publishEvent(mediaNotFoundEvent);
+        return HookResult.SUCCESS();
     }
 
     /**
@@ -800,15 +255,16 @@
         ZLMServerConfig zlmServerConfig = JSON.to(ZLMServerConfig.class, jsonObject);
         zlmServerConfig.setIp(request.getRemoteAddr());
         logger.info("[ZLM HOOK] zlm 鍚姩 " + zlmServerConfig.getGeneralMediaServerId());
-        taskExecutor.execute(() -> {
-            List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);
-            if (subscribes != null && !subscribes.isEmpty()) {
-                for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
-                    subscribe.response(null, zlmServerConfig);
-                }
+        try {
+            HookZlmServerStartEvent event = new HookZlmServerStartEvent(this);
+            MediaServer mediaServerItem = mediaServerService.getOne(zlmServerConfig.getMediaServerId());
+            if (mediaServerItem != null) {
+                event.setMediaServerItem(mediaServerItem);
+                applicationEventPublisher.publishEvent(event);
             }
-            mediaServerService.zlmServerOnline(zlmServerConfig);
-        });
+        }catch (Exception e) {
+            logger.info("[ZLM-HOOK-ZLM鍚姩] 鍙戦�侀�氱煡澶辫触 ", e);
+        }
 
         return HookResult.SUCCESS();
     }
@@ -826,22 +282,16 @@
         if (!"rtp".equals(param.getApp())) {
             return HookResult.SUCCESS();
         }
-        taskExecutor.execute(() -> {
-            List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());
-            if (sendRtpItems.size() > 0) {
-                for (SendRtpItem sendRtpItem : sendRtpItems) {
-                    ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
-                    ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
-                    try {
-                        commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
-                    } catch (SipException | InvalidArgumentException | ParseException e) {
-                        logger.error("[鍛戒护鍙戦�佸け璐 鍥芥爣绾ц仈 鍙戦�丅YE: {}", e.getMessage());
-                    }
-                    redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
-                            sendRtpItem.getCallId(), sendRtpItem.getStream());
-                }
+        try {
+            MediaSendRtpStoppedEvent event = new MediaSendRtpStoppedEvent(this);
+            MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
+            if (mediaServerItem != null) {
+                event.setMediaServer(mediaServerItem);
+                applicationEventPublisher.publishEvent(event);
             }
-        });
+        }catch (Exception e) {
+            logger.info("[ZLM-HOOK-rtp鍙戦�佸叧闂璢 鍙戦�侀�氱煡澶辫触 ", e);
+        }
 
         return HookResult.SUCCESS();
     }
@@ -855,14 +305,17 @@
             param) {
         logger.info("[ZLM HOOK] rtpServer鏀舵祦瓒呮椂锛歿}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc());
 
-        taskExecutor.execute(() -> {
-            List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout);
-            if (subscribes != null && !subscribes.isEmpty()) {
-                for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
-                    subscribe.response(null, param);
-                }
+        try {
+            MediaRtpServerTimeoutEvent event = new MediaRtpServerTimeoutEvent(this);
+            MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
+            if (mediaServerItem != null) {
+                event.setMediaServer(mediaServerItem);
+                event.setApp("rtp");
+                applicationEventPublisher.publishEvent(event);
             }
-        });
+        }catch (Exception e) {
+            logger.info("[ZLM-HOOK-rtpServer鏀舵祦瓒呮椂] 鍙戦�侀�氱煡澶辫触 ", e);
+        }
 
         return HookResult.SUCCESS();
     }
@@ -875,16 +328,16 @@
     public HookResult onRecordMp4(HttpServletRequest request, @RequestBody OnRecordMp4HookParam param) {
         logger.info("[ZLM HOOK] 褰曞儚瀹屾垚浜嬩欢锛歿}->{}", param.getMediaServerId(), param.getFile_path());
 
-        taskExecutor.execute(() -> {
-            List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_record_mp4);
-            if (subscribes != null && !subscribes.isEmpty()) {
-                for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
-                    subscribe.response(null, param);
-                }
+        try {
+            MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
+            if (mediaServerItem != null) {
+                MediaRecordMp4Event event = MediaRecordMp4Event.getInstance(this, param, mediaServerItem);
+                event.setMediaServer(mediaServerItem);
+                applicationEventPublisher.publishEvent(event);
             }
-            cloudRecordService.addRecord(param);
-
-        });
+        }catch (Exception e) {
+            logger.info("[ZLM-HOOK-rtpServer鏀舵祦瓒呮椂] 鍙戦�侀�氱煡澶辫触 ", e);
+        }
 
         return HookResult.SUCCESS();
     }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
index cbc5fde..84df2e7 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
@@ -2,12 +2,13 @@
 
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
 import com.genersoft.iot.vmp.media.zlm.dto.*;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IStreamProxyService;
 import com.genersoft.iot.vmp.service.IStreamPushService;
-import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
 import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
 import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
@@ -31,12 +32,6 @@
     private Logger logger = LoggerFactory.getLogger("ZLMMediaListManager");
 
     @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
-
-    @Autowired
-    private IRedisCatchStorage redisCatchStorage;
-
-    @Autowired
     private IVideoManagerStorage storager;
 
     @Autowired
@@ -55,7 +50,7 @@
     private StreamPushMapper streamPushMapper;
 
     @Autowired
-    private ZlmHttpHookSubscribe subscribe;
+    private HookSubscribe subscribe;
 
     @Autowired
     private UserSetting userSetting;
@@ -95,9 +90,9 @@
     }
 
     public void sendStreamEvent(String app, String stream, String mediaServerId) {
-        MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
+        MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId);
         // 鏌ョ湅鎺ㄦ祦鐘舵��
-        Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, app, stream);
+        Boolean streamReady = mediaServerService.isStreamReady(mediaServerItem, app, stream);
         if (streamReady != null && streamReady) {
             ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(app, stream);
             if (channelOnlineEventLister != null)  {
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java
new file mode 100644
index 0000000..707ea01
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java
@@ -0,0 +1,349 @@
+package com.genersoft.iot.vmp.media.zlm;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.common.CommonCallback;
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
+import com.genersoft.iot.vmp.media.service.IMediaNodeServerService;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.ZLMServerConfig;
+import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
+import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.ObjectUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service("zlm")
+public class ZLMMediaNodeServerService implements IMediaNodeServerService {
+
+    private final static Logger logger = LoggerFactory.getLogger(ZLMMediaNodeServerService.class);
+
+    @Autowired
+    private ZLMRESTfulUtils zlmresTfulUtils;
+
+    @Autowired
+    private ZLMServerFactory zlmServerFactory;
+
+    @Value("${sip.ip}")
+    private String sipIp;
+
+    @Override
+    public int createRTPServer(MediaServer mediaServer, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode) {
+        return zlmServerFactory.createRTPServer(mediaServer, streamId, ssrc, port, onlyAuto, reUsePort, tcpMode);
+    }
+
+    @Override
+    public void closeRtpServer(MediaServer mediaServer, String streamId) {
+        zlmServerFactory.closeRtpServer(mediaServer, streamId);
+    }
+
+    @Override
+    public void closeRtpServer(MediaServer mediaServer, String streamId, CommonCallback<Boolean> callback) {
+        zlmServerFactory.closeRtpServer(mediaServer, streamId, callback);
+    }
+
+    @Override
+    public void closeStreams(MediaServer mediaServer, String app, String stream) {
+        zlmresTfulUtils.closeStreams(mediaServer, app, stream);
+    }
+
+    @Override
+    public Boolean updateRtpServerSSRC(MediaServer mediaServer, String streamId, String ssrc) {
+        return zlmServerFactory.updateRtpServerSSRC(mediaServer, streamId, ssrc);
+    }
+
+    @Override
+    public boolean checkNodeId(MediaServer mediaServer) {
+        if (mediaServer == null) {
+            return false;
+        }
+        JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServer);
+        if (responseJSON != null) {
+            JSONArray data = responseJSON.getJSONArray("data");
+            if (data != null && !data.isEmpty()) {
+                ZLMServerConfig zlmServerConfig= JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
+                return zlmServerConfig.getGeneralMediaServerId().equals(mediaServer.getId());
+            }else {
+                return false;
+            }
+
+        }else {
+            return false;
+        }
+    }
+
+    @Override
+    public void online(MediaServer mediaServer) {
+
+    }
+
+    @Override
+    public MediaServer checkMediaServer(String ip, int port, String secret) {
+        MediaServer mediaServer = new MediaServer();
+        mediaServer.setIp(ip);
+        mediaServer.setHttpPort(port);
+        mediaServer.setSecret(secret);
+        JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServer);
+        if (responseJSON == null) {
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "杩炴帴澶辫触");
+        }
+        JSONArray data = responseJSON.getJSONArray("data");
+        if (data == null) {
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "璇诲彇閰嶇疆澶辫触");
+        }
+        ZLMServerConfig zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
+        if (zlmServerConfig == null) {
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "璇诲彇閰嶇疆澶辫触");
+        }
+        mediaServer.setId(zlmServerConfig.getGeneralMediaServerId());
+        mediaServer.setHttpSSlPort(zlmServerConfig.getHttpPort());
+        mediaServer.setRtmpPort(zlmServerConfig.getRtmpPort());
+        mediaServer.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
+        mediaServer.setRtspPort(zlmServerConfig.getRtspPort());
+        mediaServer.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
+        mediaServer.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
+        mediaServer.setStreamIp(ip);
+        mediaServer.setHookIp(sipIp.split(",")[0]);
+        mediaServer.setSdpIp(ip);
+        mediaServer.setType("zlm");
+        return mediaServer;
+    }
+
+    @Override
+    public boolean stopSendRtp(MediaServer mediaInfo, String app, String stream, String ssrc) {
+        Map<String, Object> param = new HashMap<>();
+        param.put("vhost", "__defaultVhost__");
+        param.put("app", app);
+        param.put("stream", stream);
+        if (!ObjectUtils.isEmpty(ssrc)) {
+            param.put("ssrc", ssrc);
+        }
+        JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaInfo, param);
+        return (jsonObject != null && jsonObject.getInteger("code") == 0);
+
+    }
+
+    @Override
+    public boolean deleteRecordDirectory(MediaServer mediaServer, String app, String stream, String date, String fileName) {
+        logger.info("[zlm-deleteRecordDirectory] 鍒犻櫎纾佺洏鏂囦欢, server: {} {}:{}->{}/{}", mediaServer.getId(), app, stream, date, fileName);
+        JSONObject jsonObject = zlmresTfulUtils.deleteRecordDirectory(mediaServer, app,
+                stream, date, fileName);
+        if (jsonObject.getInteger("code") == 0) {
+            return true;
+        }else {
+            logger.info("[zlm-deleteRecordDirectory] 鍒犻櫎纾佺洏鏂囦欢閿欒, server: {} {}:{}->{}/{}, 缁撴灉锛� {}", mediaServer.getId(), app, stream, date, fileName, jsonObject);
+            return false;
+        }
+    }
+
+    @Override
+    public List<StreamInfo> getMediaList(MediaServer mediaServer, String app, String stream, String callId) {
+        List<StreamInfo> streamInfoList = new ArrayList<>();
+        JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaServer, app, stream);
+        if (mediaList != null) {
+            if (mediaList.getInteger("code") == 0) {
+                JSONArray data = mediaList.getJSONArray("data");
+                if (data == null) {
+                    return null;
+                }
+                JSONObject mediaJSON = data.getJSONObject(0);
+                MediaInfo mediaInfo = MediaInfo.getInstance(mediaJSON, mediaServer);
+                StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, app, stream, mediaInfo, callId, true);
+                if (streamInfo != null) {
+                    streamInfoList.add(streamInfo);
+                }
+            }
+        }
+        return streamInfoList;
+    }
+
+    public StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServer, String app, String stream, MediaInfo mediaInfo, String callId, boolean isPlay) {
+        StreamInfo streamInfoResult = new StreamInfo();
+        streamInfoResult.setStream(stream);
+        streamInfoResult.setApp(app);
+        String addr = mediaServer.getStreamIp();
+        streamInfoResult.setIp(addr);
+        streamInfoResult.setMediaServerId(mediaServer.getId());
+        String callIdParam = ObjectUtils.isEmpty(callId)?"":"?callId=" + callId;
+        streamInfoResult.setRtmp(addr, mediaServer.getRtmpPort(),mediaServer.getRtmpSSlPort(), app,  stream, callIdParam);
+        streamInfoResult.setRtsp(addr, mediaServer.getRtspPort(),mediaServer.getRtspSSLPort(), app,  stream, callIdParam);
+        String flvFile = String.format("%s/%s.live.flv%s", app, stream, callIdParam);
+        streamInfoResult.setFlv(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), flvFile);
+        streamInfoResult.setWsFlv(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), flvFile);
+        streamInfoResult.setFmp4(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app,  stream, callIdParam);
+        streamInfoResult.setHls(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app,  stream, callIdParam);
+        streamInfoResult.setTs(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app,  stream, callIdParam);
+        streamInfoResult.setRtc(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app,  stream, callIdParam, isPlay);
+
+        streamInfoResult.setMediaInfo(mediaInfo);
+        streamInfoResult.setOriginType(mediaInfo.getOriginType());
+        return streamInfoResult;
+    }
+
+    @Override
+    public Boolean connectRtpServer(MediaServer mediaServer, String address, int port, String stream) {
+        JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServer, address, port, stream);
+        logger.info("[TCP涓诲姩杩炴帴瀵规柟] 缁撴灉锛� {}", jsonObject);
+        return jsonObject.getInteger("code") == 0;
+    }
+
+    @Override
+    public void getSnap(MediaServer mediaServer, String streamUrl, int timeoutSec, int expireSec, String path, String fileName) {
+        zlmresTfulUtils.getSnap(mediaServer, streamUrl, timeoutSec, expireSec, path, fileName);
+    }
+
+    @Override
+    public MediaInfo getMediaInfo(MediaServer mediaServer, String app, String stream) {
+        JSONObject jsonObject = zlmresTfulUtils.getMediaInfo(mediaServer, app, "rtsp", stream);
+        if (jsonObject.getInteger("code") != 0) {
+            return null;
+        }
+        return MediaInfo.getInstance(jsonObject, mediaServer);
+    }
+
+    @Override
+    public Boolean pauseRtpCheck(MediaServer mediaServer, String streamKey) {
+        JSONObject jsonObject = zlmresTfulUtils.pauseRtpCheck(mediaServer, streamKey);
+        return jsonObject.getInteger("code") == 0;
+    }
+
+    @Override
+    public Boolean resumeRtpCheck(MediaServer mediaServer, String streamKey) {
+        JSONObject jsonObject = zlmresTfulUtils.resumeRtpCheck(mediaServer, streamKey);
+        return jsonObject.getInteger("code") == 0;
+    }
+
+    @Override
+    public String getFfmpegCmd(MediaServer mediaServer, String cmdKey) {
+        JSONObject jsonObject = zlmresTfulUtils.getMediaServerConfig(mediaServer);
+        if (jsonObject.getInteger("code") != 0) {
+            logger.warn("[getFfmpegCmd] 鑾峰彇娴佸獟浣撻厤缃け璐�");
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "鑾峰彇娴佸獟浣撻厤缃け璐�");
+        }
+        JSONArray dataArray = jsonObject.getJSONArray("data");
+        JSONObject mediaServerConfig = dataArray.getJSONObject(0);
+        if (ObjectUtils.isEmpty(cmdKey)) {
+            cmdKey = "ffmpeg.cmd";
+        }
+       return mediaServerConfig.getString(cmdKey);
+    }
+
+    @Override
+    public WVPResult<String> addFFmpegSource(MediaServer mediaServer, String srcUrl, String dstUrl, int timeoutMs, boolean enableAudio, boolean enableMp4, String ffmpegCmdKey) {
+        JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(mediaServer, srcUrl, dstUrl, timeoutMs, enableAudio, enableMp4, ffmpegCmdKey);
+        if (jsonObject.getInteger("code") != 0) {
+            logger.warn("[getFfmpegCmd] 娣诲姞FFMPEG浠g悊澶辫触");
+            return WVPResult.fail(ErrorCode.ERROR100.getCode(), "娣诲姞FFMPEG浠g悊澶辫触");
+        }else {
+            JSONObject data = jsonObject.getJSONObject("data");
+            if (data == null) {
+                return WVPResult.fail(ErrorCode.ERROR100.getCode(), "浠g悊缁撴灉寮傚父锛� " + jsonObject);
+            }else {
+                return WVPResult.success(data.getString("key"));
+            }
+        }
+    }
+
+    @Override
+    public WVPResult<String> addStreamProxy(MediaServer mediaServer, String app, String stream, String url, boolean enableAudio, boolean enableMp4, String rtpType) {
+        JSONObject jsonObject = zlmresTfulUtils.addStreamProxy(mediaServer, app, stream, url, enableAudio, enableMp4, rtpType);
+        if (jsonObject.getInteger("code") != 0) {
+            return WVPResult.fail(ErrorCode.ERROR100.getCode(), "娣诲姞浠g悊澶辫触");
+        }else {
+            JSONObject data = jsonObject.getJSONObject("data");
+            if (data == null) {
+                return WVPResult.fail(ErrorCode.ERROR100.getCode(), "浠g悊缁撴灉寮傚父锛� " + jsonObject);
+            }else {
+                return WVPResult.success(data.getString("key"));
+            }
+        }
+    }
+
+    @Override
+    public Boolean delFFmpegSource(MediaServer mediaServer, String streamKey) {
+        JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(mediaServer, streamKey);
+        return jsonObject.getInteger("code") == 0;
+    }
+
+    @Override
+    public Boolean delStreamProxy(MediaServer mediaServer, String streamKey) {
+        JSONObject jsonObject = zlmresTfulUtils.delStreamProxy(mediaServer, streamKey);
+        return jsonObject.getInteger("code") == 0;
+    }
+
+    @Override
+    public Map<String, String> getFFmpegCMDs(MediaServer mediaServer) {
+        Map<String, String> result = new HashMap<>();
+        JSONObject mediaServerConfigResuly = zlmresTfulUtils.getMediaServerConfig(mediaServer);
+        if (mediaServerConfigResuly != null && mediaServerConfigResuly.getInteger("code") == 0
+                && mediaServerConfigResuly.getJSONArray("data").size() > 0){
+            JSONObject mediaServerConfig = mediaServerConfigResuly.getJSONArray("data").getJSONObject(0);
+
+            for (String key : mediaServerConfig.keySet()) {
+                if (key.startsWith("ffmpeg.cmd")){
+                    result.put(key, mediaServerConfig.getString(key));
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void startSendRtpPassive(MediaServer mediaServer, SendRtpItem sendRtpItem, Integer timeout) {
+        Map<String, Object> param = new HashMap<>(12);
+        param.put("vhost","__defaultVhost__");
+        param.put("app", sendRtpItem.getApp());
+        param.put("stream", sendRtpItem.getStream());
+        param.put("ssrc", sendRtpItem.getSsrc());
+        param.put("src_port", sendRtpItem.getLocalPort());
+        param.put("pt", sendRtpItem.getPt());
+        param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
+        param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
+        param.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");
+        param.put("recv_stream_id", sendRtpItem.getReceiveStream());
+        if (timeout  != null) {
+            param.put("close_delay_ms", timeout);
+        }
+
+        JSONObject jsonObject = zlmServerFactory.startSendRtpPassive(mediaServer, param, null);
+        if (jsonObject == null || jsonObject.getInteger("code") != 0 ) {
+            throw new ControllerException(jsonObject.getInteger("code"), jsonObject.getString("msg"));
+        }
+    }
+
+    @Override
+    public void startSendRtpStream(MediaServer mediaServer, SendRtpItem sendRtpItem) {
+        Map<String, Object> param = new HashMap<>(12);
+        param.put("vhost", "__defaultVhost__");
+        param.put("app", sendRtpItem.getApp());
+        param.put("stream", sendRtpItem.getStream());
+        param.put("ssrc", sendRtpItem.getSsrc());
+        param.put("src_port", sendRtpItem.getLocalPort());
+        param.put("pt", sendRtpItem.getPt());
+        param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
+        param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
+        param.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");
+        if (!sendRtpItem.isTcp()) {
+            // udp妯″紡涓嬪紑鍚痳tcp淇濇椿
+            param.put("udp_rtcp_timeout", sendRtpItem.isRtcp() ? "1" : "0");
+        }
+        param.put("dst_url", sendRtpItem.getIp());
+        param.put("dst_port", sendRtpItem.getPort());
+        JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServer, param);
+        if (jsonObject == null || jsonObject.getInteger("code") != 0 ) {
+            throw new ControllerException(jsonObject.getInteger("code"), jsonObject.getString("msg"));
+        }
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManger.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManger.java
new file mode 100644
index 0000000..cdf1e3f
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManger.java
@@ -0,0 +1,306 @@
+package com.genersoft.iot.vmp.media.zlm;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.conf.DynamicTask;
+import com.genersoft.iot.vmp.conf.UserSetting;
+import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerChangeEvent;
+import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerDeleteEvent;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.ZLMServerConfig;
+import com.genersoft.iot.vmp.media.zlm.event.HookZlmServerKeepaliveEvent;
+import com.genersoft.iot.vmp.media.zlm.event.HookZlmServerStartEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ObjectUtils;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 绠$悊zlm娴佸獟浣撹妭鐐圭殑鐘舵��
+ */
+@Component
+public class ZLMMediaServerStatusManger {
+
+    private final static Logger logger = LoggerFactory.getLogger(ZLMMediaServerStatusManger.class);
+
+    private final Map<Object, MediaServer> offlineZlmPrimaryMap = new ConcurrentHashMap<>();
+    private final Map<Object, MediaServer> offlineZlmsecondaryMap = new ConcurrentHashMap<>();
+    private final Map<Object, Long> offlineZlmTimeMap = new ConcurrentHashMap<>();
+
+    @Autowired
+    private ZLMRESTfulUtils zlmresTfulUtils;
+
+    @Autowired
+    private IMediaServerService mediaServerService;
+
+    @Autowired
+    private DynamicTask dynamicTask;
+
+    @Value("${server.ssl.enabled:false}")
+    private boolean sslEnabled;
+
+    @Value("${server.port}")
+    private Integer serverPort;
+
+    @Value("${server.servlet.context-path:}")
+    private String serverServletContextPath;
+
+    @Autowired
+    private UserSetting userSetting;
+
+    private final String type = "zlm";
+
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaServerChangeEvent event) {
+        if (event.getMediaServerItemList() == null
+                || event.getMediaServerItemList().isEmpty()) {
+            return;
+        }
+        for (MediaServer mediaServerItem : event.getMediaServerItemList()) {
+            if (!type.equals(mediaServerItem.getType())) {
+                continue;
+            }
+            logger.info("[ZLM-娣诲姞寰呬笂绾胯妭鐐筣 ID锛�" + mediaServerItem.getId());
+            offlineZlmPrimaryMap.put(mediaServerItem.getId(), mediaServerItem);
+            offlineZlmTimeMap.put(mediaServerItem.getId(), System.currentTimeMillis());
+            execute();
+        }
+    }
+
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(HookZlmServerStartEvent event) {
+        if (event.getMediaServerItem() == null
+                || !type.equals(event.getMediaServerItem().getType())
+                || event.getMediaServerItem().isStatus()) {
+            return;
+        }
+        MediaServer serverItem = mediaServerService.getOne(event.getMediaServerItem().getId());
+        if (serverItem == null) {
+            return;
+        }
+        logger.info("[ZLM-HOOK浜嬩欢-鏈嶅姟鍚姩] ID锛�" + event.getMediaServerItem().getId());
+        online(serverItem, null);
+    }
+
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(HookZlmServerKeepaliveEvent event) {
+        if (event.getMediaServerItem() == null) {
+            return;
+        }
+        MediaServer serverItem = mediaServerService.getOne(event.getMediaServerItem().getId());
+        if (serverItem == null) {
+            return;
+        }
+        logger.info("[ZLM-HOOK浜嬩欢-蹇冭烦] ID锛�" + event.getMediaServerItem().getId());
+        online(serverItem, null);
+    }
+
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaServerDeleteEvent event) {
+        if (event.getMediaServerId() == null) {
+            return;
+        }
+        logger.info("[ZLM-鑺傜偣琚Щ闄 ID锛�" + event.getMediaServerId());
+        offlineZlmPrimaryMap.remove(event.getMediaServerId());
+        offlineZlmsecondaryMap.remove(event.getMediaServerId());
+        offlineZlmTimeMap.remove(event.getMediaServerId());
+    }
+
+    @Scheduled(fixedDelay = 10*1000)   //姣忛殧10绉掓鏌ヤ竴娆�
+    public void execute(){
+        // 鍒濇鍔犲叆鐨勭绾胯妭鐐逛細鍦�30鍒嗛挓鍐咃紝姣忛棿闅斿崄绉掑皾璇曚竴娆★紝30鍒嗛挓鍚庡鏋滀粛鐒舵病鏈変笂绾匡紝鍒欐瘡闅�30鍒嗛挓灏濊瘯涓�娆¤繛鎺�
+        if (offlineZlmPrimaryMap.isEmpty() && offlineZlmsecondaryMap.isEmpty()) {
+            return;
+        }
+        if (!offlineZlmPrimaryMap.isEmpty()) {
+            for (MediaServer mediaServerItem : offlineZlmPrimaryMap.values()) {
+                if (offlineZlmTimeMap.get(mediaServerItem.getId()) <  System.currentTimeMillis() - 30*60*1000) {
+                    offlineZlmsecondaryMap.put(mediaServerItem.getId(), mediaServerItem);
+                    offlineZlmPrimaryMap.remove(mediaServerItem.getId());
+                    continue;
+                }
+                logger.info("[ZLM-灏濊瘯杩炴帴] ID锛歿}, 鍦板潃锛� {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+                JSONObject responseJson = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
+                ZLMServerConfig zlmServerConfig = null;
+                if (responseJson == null) {
+                    logger.info("[ZLM-灏濊瘯杩炴帴]澶辫触, ID锛歿}, 鍦板潃锛� {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+                    continue;
+                }
+                JSONArray data = responseJson.getJSONArray("data");
+                if (data == null || data.isEmpty()) {
+                    logger.info("[ZLM-灏濊瘯杩炴帴]澶辫触, ID锛歿}, 鍦板潃锛� {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+                }else {
+                    zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
+                    initPort(mediaServerItem, zlmServerConfig);
+                    online(mediaServerItem, zlmServerConfig);
+                }
+            }
+        }
+        if (!offlineZlmsecondaryMap.isEmpty()) {
+            for (MediaServer mediaServerItem : offlineZlmsecondaryMap.values()) {
+                if (offlineZlmTimeMap.get(mediaServerItem.getId()) <  System.currentTimeMillis() - 30*60*1000) {
+                    continue;
+                }
+                logger.info("[ZLM-灏濊瘯杩炴帴] ID锛歿}, 鍦板潃锛� {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+                JSONObject responseJson = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
+                ZLMServerConfig zlmServerConfig = null;
+                if (responseJson == null) {
+                    logger.info("[ZLM-灏濊瘯杩炴帴]澶辫触, ID锛歿}, 鍦板潃锛� {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+                    offlineZlmTimeMap.put(mediaServerItem.getId(), System.currentTimeMillis());
+                    continue;
+                }
+                JSONArray data = responseJson.getJSONArray("data");
+                if (data == null || data.isEmpty()) {
+                    logger.info("[ZLM-灏濊瘯杩炴帴]澶辫触, ID锛歿}, 鍦板潃锛� {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+                    offlineZlmTimeMap.put(mediaServerItem.getId(), System.currentTimeMillis());
+                }else {
+                    zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
+                    initPort(mediaServerItem, zlmServerConfig);
+                    online(mediaServerItem, zlmServerConfig);
+                }
+            }
+        }
+    }
+
+    private void online(MediaServer mediaServerItem, ZLMServerConfig config) {
+        offlineZlmPrimaryMap.remove(mediaServerItem.getId());
+        offlineZlmsecondaryMap.remove(mediaServerItem.getId());
+        offlineZlmTimeMap.remove(mediaServerItem.getId());
+        if (!mediaServerItem.isStatus()) {
+            logger.info("[ZLM-杩炴帴鎴愬姛] ID锛歿}, 鍦板潃锛� {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+            mediaServerItem.setStatus(true);
+            mediaServerItem.setHookAliveInterval(10F);
+            mediaServerService.update(mediaServerItem);
+            if(mediaServerItem.isAutoConfig()) {
+                if (config == null) {
+                    JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
+                    JSONArray data = responseJSON.getJSONArray("data");
+                    if (data != null && !data.isEmpty()) {
+                        config = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
+                    }
+                }
+                if (config != null) {
+                    initPort(mediaServerItem, config);
+                    setZLMConfig(mediaServerItem, "0".equals(config.getHookEnable())
+                            || !Objects.equals(mediaServerItem.getHookAliveInterval(), config.getHookAliveInterval()));
+                }
+            }
+            mediaServerService.update(mediaServerItem);
+        }
+        // 璁剧疆涓ゆ蹇冭烦鏈敹鍒板垯璁や负zlm绂荤嚎
+        String key = "zlm-keepalive-" + mediaServerItem.getId();
+        dynamicTask.startDelay(key, ()->{
+            logger.warn("[ZLM-蹇冭烦瓒呮椂] ID锛歿}", mediaServerItem.getId());
+            mediaServerItem.setStatus(false);
+            offlineZlmPrimaryMap.put(mediaServerItem.getId(), mediaServerItem);
+            offlineZlmTimeMap.put(mediaServerItem.getId(), System.currentTimeMillis());
+            // TODO 鍙戦�佺绾块�氱煡
+            mediaServerService.update(mediaServerItem);
+        }, (int)(mediaServerItem.getHookAliveInterval() * 2 * 1000));
+    }
+    private void initPort(MediaServer mediaServerItem, ZLMServerConfig zlmServerConfig) {
+        // 绔彛鍙細浠庨厤缃腑璇诲彇涓�娆★紝涓�鏃﹁嚜宸遍厤缃垨鑰呰鍙栬繃浜嗗皢涓嶅湪閰嶇疆
+        if (mediaServerItem.getHttpSSlPort() == 0) {
+            mediaServerItem.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
+        }
+        if (mediaServerItem.getRtmpPort() == 0) {
+            mediaServerItem.setRtmpPort(zlmServerConfig.getRtmpPort());
+        }
+        if (mediaServerItem.getRtmpSSlPort() == 0) {
+            mediaServerItem.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
+        }
+        if (mediaServerItem.getRtspPort() == 0) {
+            mediaServerItem.setRtspPort(zlmServerConfig.getRtspPort());
+        }
+        if (mediaServerItem.getRtspSSLPort() == 0) {
+            mediaServerItem.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
+        }
+        if (mediaServerItem.getRtpProxyPort() == 0) {
+            mediaServerItem.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
+        }
+        mediaServerItem.setHookAliveInterval(10F);
+    }
+
+    public void setZLMConfig(MediaServer mediaServerItem, boolean restart) {
+        logger.info("[濯掍綋鏈嶅姟鑺傜偣] 姝e湪璁剧疆 锛歿} -> {}:{}",
+                mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+        String protocol = sslEnabled ? "https" : "http";
+        String hookPrefix = String.format("%s://%s:%s%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort, (serverServletContextPath == null || "/".equals(serverServletContextPath)) ? "" : serverServletContextPath);
+
+        Map<String, Object> param = new HashMap<>();
+        param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline
+        if (mediaServerItem.getRtspPort() != 0) {
+            param.put("ffmpeg.snap", "%s -rtsp_transport tcp -i %s -y -f mjpeg -frames:v 1 %s");
+        }
+        param.put("hook.enable","1");
+        param.put("hook.on_flow_report","");
+        param.put("hook.on_play",String.format("%s/on_play", hookPrefix));
+        param.put("hook.on_http_access","");
+        param.put("hook.on_publish", String.format("%s/on_publish", hookPrefix));
+        param.put("hook.on_record_ts","");
+        param.put("hook.on_rtsp_auth","");
+        param.put("hook.on_rtsp_realm","");
+        param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrefix));
+        param.put("hook.on_shell_login","");
+        param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrefix));
+        param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrefix));
+        param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrefix));
+        param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrefix));
+        param.put("hook.on_send_rtp_stopped",String.format("%s/on_send_rtp_stopped", hookPrefix));
+        param.put("hook.on_rtp_server_timeout",String.format("%s/on_rtp_server_timeout", hookPrefix));
+        param.put("hook.on_record_mp4",String.format("%s/on_record_mp4", hookPrefix));
+        param.put("hook.timeoutSec","30");
+        param.put("hook.alive_interval", mediaServerItem.getHookAliveInterval());
+        // 鎺ㄦ祦鏂紑鍚庡彲浠ュ湪瓒呮椂鏃堕棿鍐呴噸鏂拌繛鎺ヤ笂缁х画鎺ㄦ祦锛岃繖鏍锋挱鏀惧櫒浼氭帴鐫�鎾斁銆�
+        // 缃�0鍏抽棴姝ょ壒鎬�(鎺ㄦ祦鏂紑浼氬鑷寸珛鍗虫柇寮�鎾斁鍣�)
+        // 姝ゅ弬鏁颁笉搴斿ぇ浜庢挱鏀惧櫒瓒呮椂鏃堕棿
+        // 浼樺寲姝ゆ秷鎭互鏇村揩鐨勬敹鍒版祦娉ㄩ攢浜嬩欢
+        param.put("protocol.continue_push_ms", "3000" );
+        // 鏈�澶氱瓑寰呮湭鍒濆鍖栫殑Track鏃堕棿锛屽崟浣嶆绉掞紝瓒呮椂涔嬪悗浼氬拷鐣ユ湭鍒濆鍖栫殑Track, 璁剧疆姝ら�夐」浼樺寲閭d簺闊抽閿欒鐨勪笉瑙勮寖娴侊紝
+        // 绛墇lm鏀寔缁欐瘡涓猺tpServer璁剧疆鍏抽棴闊抽鐨勬椂鍊欏彲浠ヤ笉璁剧疆姝ら�夐」
+        if (mediaServerItem.isRtpEnable() && !ObjectUtils.isEmpty(mediaServerItem.getRtpPortRange())) {
+            param.put("rtp_proxy.port_range", mediaServerItem.getRtpPortRange().replace(",", "-"));
+        }
+
+        if (!ObjectUtils.isEmpty(mediaServerItem.getRecordPath())) {
+            File recordPathFile = new File(mediaServerItem.getRecordPath());
+            param.put("protocol.mp4_save_path", recordPathFile.getParentFile().getPath());
+            param.put("protocol.downloadRoot", recordPathFile.getParentFile().getPath());
+            param.put("record.appName", recordPathFile.getName());
+        }
+
+        JSONObject responseJSON = zlmresTfulUtils.setServerConfig(mediaServerItem, param);
+
+        if (responseJSON != null && responseJSON.getInteger("code") == 0) {
+            if (restart) {
+                logger.info("[濯掍綋鏈嶅姟鑺傜偣] 璁剧疆鎴愬姛,寮�濮嬮噸鍚互淇濊瘉閰嶇疆鐢熸晥 {} -> {}:{}",
+                        mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+                zlmresTfulUtils.restartServer(mediaServerItem);
+            }else {
+                logger.info("[濯掍綋鏈嶅姟鑺傜偣] 璁剧疆鎴愬姛 {} -> {}:{}",
+                        mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+            }
+        }else {
+            logger.info("[濯掍綋鏈嶅姟鑺傜偣] 璁剧疆濯掍綋鏈嶅姟鑺傜偣澶辫触 {} -> {}:{}",
+                    mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+        }
+    }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
index 044f9f3..285b9e6 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -2,7 +2,7 @@
 
 import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import okhttp3.*;
 import okhttp3.logging.HttpLoggingInterceptor;
 import org.jetbrains.annotations.NotNull;
@@ -60,12 +60,12 @@
 
     }
 
-    public JSONObject sendPost(MediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
+    public JSONObject sendPost(MediaServer mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
         return sendPost(mediaServerItem, api, param, callback, null);
     }
 
 
-    public JSONObject sendPost(MediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback, Integer readTimeOut) {
+    public JSONObject sendPost(MediaServer mediaServerItem, String api, Map<String, Object> param, RequestCallback callback, Integer readTimeOut) {
         OkHttpClient client = getClient(readTimeOut);
 
         if (mediaServerItem == null) {
@@ -104,8 +104,6 @@
                             responseJSON = JSON.parseObject(responseStr);
                         }
                     }else {
-                        System.out.println( 2222);
-                        System.out.println( response.code());
                         response.close();
                         Objects.requireNonNull(response.body()).close();
                     }
@@ -164,7 +162,7 @@
         return responseJSON;
     }
 
-    public void sendGetForImg(MediaServerItem mediaServerItem, String api, Map<String, Object> params, String targetPath, String fileName) {
+    public void sendGetForImg(MediaServer mediaServerItem, String api, Map<String, Object> params, String targetPath, String fileName) {
         String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
         HttpUrl parseUrl = HttpUrl.parse(url);
         if (parseUrl == null) {
@@ -216,7 +214,7 @@
         }
     }
 
-    public JSONObject isMediaOnline(MediaServerItem mediaServerItem, String app, String stream, String schema){
+    public JSONObject isMediaOnline(MediaServer mediaServerItem, String app, String stream, String schema){
         Map<String, Object> param = new HashMap<>();
         if (app != null) {
             param.put("app",app);
@@ -231,7 +229,7 @@
         return sendPost(mediaServerItem, "isMediaOnline", param, null);
     }
 
-    public JSONObject getMediaList(MediaServerItem mediaServerItem, String app, String stream, String schema, RequestCallback callback){
+    public JSONObject getMediaList(MediaServer mediaServerItem, String app, String stream, String schema, RequestCallback callback){
         Map<String, Object> param = new HashMap<>();
         if (app != null) {
             param.put("app",app);
@@ -246,15 +244,15 @@
         return sendPost(mediaServerItem, "getMediaList",param, callback);
     }
 
-    public JSONObject getMediaList(MediaServerItem mediaServerItem, String app, String stream){
+    public JSONObject getMediaList(MediaServer mediaServerItem, String app, String stream){
         return getMediaList(mediaServerItem, app, stream,null,  null);
     }
 
-    public JSONObject getMediaList(MediaServerItem mediaServerItem, RequestCallback callback){
+    public JSONObject getMediaList(MediaServer mediaServerItem, RequestCallback callback){
         return sendPost(mediaServerItem, "getMediaList",null, callback);
     }
 
-    public JSONObject getMediaInfo(MediaServerItem mediaServerItem, String app, String schema, String stream){
+    public JSONObject getMediaInfo(MediaServer mediaServerItem, String app, String schema, String stream){
         Map<String, Object> param = new HashMap<>();
         param.put("app",app);
         param.put("schema",schema);
@@ -263,13 +261,13 @@
         return sendPost(mediaServerItem, "getMediaInfo",param, null);
     }
 
-    public JSONObject getRtpInfo(MediaServerItem mediaServerItem, String stream_id){
+    public JSONObject getRtpInfo(MediaServer mediaServerItem, String stream_id){
         Map<String, Object> param = new HashMap<>();
         param.put("stream_id",stream_id);
         return sendPost(mediaServerItem, "getRtpInfo",param, null);
     }
 
-    public JSONObject addFFmpegSource(MediaServerItem mediaServerItem, String src_url, String dst_url, String timeout_ms,
+    public JSONObject addFFmpegSource(MediaServer mediaServerItem, String src_url, String dst_url, Integer timeout_ms,
                                       boolean enable_audio, boolean enable_mp4, String ffmpeg_cmd_key){
         logger.info(src_url);
         logger.info(dst_url);
@@ -282,63 +280,63 @@
         return sendPost(mediaServerItem, "addFFmpegSource",param, null);
     }
 
-    public JSONObject delFFmpegSource(MediaServerItem mediaServerItem, String key){
+    public JSONObject delFFmpegSource(MediaServer mediaServerItem, String key){
         Map<String, Object> param = new HashMap<>();
         param.put("key", key);
         return sendPost(mediaServerItem, "delFFmpegSource",param, null);
     }
 
-    public JSONObject delStreamProxy(MediaServerItem mediaServerItem, String key){
+    public JSONObject delStreamProxy(MediaServer mediaServerItem, String key){
         Map<String, Object> param = new HashMap<>();
         param.put("key", key);
         return sendPost(mediaServerItem, "delStreamProxy",param, null);
     }
 
-    public JSONObject getMediaServerConfig(MediaServerItem mediaServerItem){
+    public JSONObject getMediaServerConfig(MediaServer mediaServerItem){
         return sendPost(mediaServerItem, "getServerConfig",null, null);
     }
 
-    public JSONObject setServerConfig(MediaServerItem mediaServerItem, Map<String, Object> param){
+    public JSONObject setServerConfig(MediaServer mediaServerItem, Map<String, Object> param){
         return sendPost(mediaServerItem,"setServerConfig",param, null);
     }
 
-    public JSONObject openRtpServer(MediaServerItem mediaServerItem, Map<String, Object> param){
+    public JSONObject openRtpServer(MediaServer mediaServerItem, Map<String, Object> param){
         return sendPost(mediaServerItem, "openRtpServer",param, null);
     }
 
-    public JSONObject closeRtpServer(MediaServerItem mediaServerItem, Map<String, Object> param) {
+    public JSONObject closeRtpServer(MediaServer mediaServerItem, Map<String, Object> param) {
         return sendPost(mediaServerItem, "closeRtpServer",param, null);
     }
 
-    public void closeRtpServer(MediaServerItem mediaServerItem, Map<String, Object> param, RequestCallback callback) {
+    public void closeRtpServer(MediaServer mediaServerItem, Map<String, Object> param, RequestCallback callback) {
         sendPost(mediaServerItem, "closeRtpServer",param, callback);
     }
 
-    public JSONObject listRtpServer(MediaServerItem mediaServerItem) {
+    public JSONObject listRtpServer(MediaServer mediaServerItem) {
         return sendPost(mediaServerItem, "listRtpServer",null, null);
     }
 
-    public JSONObject startSendRtp(MediaServerItem mediaServerItem, Map<String, Object> param) {
+    public JSONObject startSendRtp(MediaServer mediaServerItem, Map<String, Object> param) {
         return sendPost(mediaServerItem, "startSendRtp",param, null);
     }
 
-    public JSONObject startSendRtpPassive(MediaServerItem mediaServerItem, Map<String, Object> param) {
+    public JSONObject startSendRtpPassive(MediaServer mediaServerItem, Map<String, Object> param) {
         return sendPost(mediaServerItem, "startSendRtpPassive",param, null);
     }
 
-    public JSONObject startSendRtpPassive(MediaServerItem mediaServerItem, Map<String, Object> param, RequestCallback callback) {
+    public JSONObject startSendRtpPassive(MediaServer mediaServerItem, Map<String, Object> param, RequestCallback callback) {
         return sendPost(mediaServerItem, "startSendRtpPassive",param, callback);
     }
 
-    public JSONObject stopSendRtp(MediaServerItem mediaServerItem, Map<String, Object> param) {
+    public JSONObject stopSendRtp(MediaServer mediaServerItem, Map<String, Object> param) {
         return sendPost(mediaServerItem, "stopSendRtp",param, null);
     }
 
-    public JSONObject restartServer(MediaServerItem mediaServerItem) {
+    public JSONObject restartServer(MediaServer mediaServerItem) {
         return sendPost(mediaServerItem, "restartServer",null, null);
     }
 
-    public JSONObject addStreamProxy(MediaServerItem mediaServerItem, String app, String stream, String url, boolean enable_audio, boolean enable_mp4, String rtp_type) {
+    public JSONObject addStreamProxy(MediaServer mediaServerItem, String app, String stream, String url, boolean enable_audio, boolean enable_mp4, String rtp_type) {
         Map<String, Object> param = new HashMap<>();
         param.put("vhost", "__defaultVhost__");
         param.put("app", app);
@@ -350,7 +348,7 @@
         return sendPost(mediaServerItem, "addStreamProxy",param, null, 20);
     }
 
-    public JSONObject closeStreams(MediaServerItem mediaServerItem, String app, String stream) {
+    public JSONObject closeStreams(MediaServer mediaServerItem, String app, String stream) {
         Map<String, Object> param = new HashMap<>();
         param.put("vhost", "__defaultVhost__");
         param.put("app", app);
@@ -359,17 +357,17 @@
         return sendPost(mediaServerItem, "close_streams",param, null);
     }
 
-    public JSONObject getAllSession(MediaServerItem mediaServerItem) {
+    public JSONObject getAllSession(MediaServer mediaServerItem) {
         return sendPost(mediaServerItem, "getAllSession",null, null);
     }
 
-    public void kickSessions(MediaServerItem mediaServerItem, String localPortSStr) {
+    public void kickSessions(MediaServer mediaServerItem, String localPortSStr) {
         Map<String, Object> param = new HashMap<>();
         param.put("local_port", localPortSStr);
         sendPost(mediaServerItem, "kick_sessions",param, null);
     }
 
-    public void getSnap(MediaServerItem mediaServerItem, String streamUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
+    public void getSnap(MediaServer mediaServerItem, String streamUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
         Map<String, Object> param = new HashMap<>(3);
         param.put("url", streamUrl);
         param.put("timeout_sec", timeout_sec);
@@ -377,19 +375,19 @@
         sendGetForImg(mediaServerItem, "getSnap", param, targetPath, fileName);
     }
 
-    public JSONObject pauseRtpCheck(MediaServerItem mediaServerItem, String streamId) {
+    public JSONObject pauseRtpCheck(MediaServer mediaServerItem, String streamId) {
         Map<String, Object> param = new HashMap<>(1);
         param.put("stream_id", streamId);
         return sendPost(mediaServerItem, "pauseRtpCheck",param, null);
     }
 
-    public JSONObject resumeRtpCheck(MediaServerItem mediaServerItem, String streamId) {
+    public JSONObject resumeRtpCheck(MediaServer mediaServerItem, String streamId) {
         Map<String, Object> param = new HashMap<>(1);
         param.put("stream_id", streamId);
         return sendPost(mediaServerItem, "resumeRtpCheck",param, null);
     }
 
-    public JSONObject connectRtpServer(MediaServerItem mediaServerItem, String dst_url, int dst_port, String stream_id) {
+    public JSONObject connectRtpServer(MediaServer mediaServerItem, String dst_url, int dst_port, String stream_id) {
         Map<String, Object> param = new HashMap<>(1);
         param.put("dst_url", dst_url);
         param.put("dst_port", dst_port);
@@ -397,14 +395,14 @@
         return sendPost(mediaServerItem, "connectRtpServer",param, null);
     }
 
-    public JSONObject updateRtpServerSSRC(MediaServerItem mediaServerItem, String streamId, String ssrc) {
+    public JSONObject updateRtpServerSSRC(MediaServer mediaServerItem, String streamId, String ssrc) {
         Map<String, Object> param = new HashMap<>(1);
         param.put("ssrc", ssrc);
         param.put("stream_id", streamId);
         return sendPost(mediaServerItem, "updateRtpServerSSRC",param, null);
     }
 
-    public JSONObject deleteRecordDirectory(MediaServerItem mediaServerItem, String app, String stream, String date, String fileName) {
+    public JSONObject deleteRecordDirectory(MediaServer mediaServerItem, String app, String stream, String date, String fileName) {
         Map<String, Object> param = new HashMap<>(1);
         param.put("vhost", "__defaultVhost__");
         param.put("app", app);
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
deleted file mode 100755
index 4a781f3..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm;
-
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONArray;
-import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.conf.DynamicTask;
-import com.genersoft.iot.vmp.conf.MediaConfig;
-import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForServerStarted;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
-import com.genersoft.iot.vmp.service.IMediaServerService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.CommandLineRunner;
-import org.springframework.core.annotation.Order;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.stereotype.Component;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-@Component
-@Order(value=12)
-public class ZLMRunner implements CommandLineRunner {
-
-    private final static Logger logger = LoggerFactory.getLogger(ZLMRunner.class);
-
-    private Map<String, Boolean> startGetMedia;
-
-    @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
-
-    @Autowired
-    private ZlmHttpHookSubscribe hookSubscribe;
-
-    @Autowired
-    private EventPublisher publisher;
-
-    @Autowired
-    private IMediaServerService mediaServerService;
-
-    @Autowired
-    private MediaConfig mediaConfig;
-
-    @Autowired
-    private DynamicTask dynamicTask;
-
-
-    @Override
-    public void run(String... strings) throws Exception {
-        mediaServerService.clearMediaServerForOnline();
-        MediaServerItem defaultMediaServer = mediaServerService.getDefaultMediaServer();
-        if (defaultMediaServer == null) {
-            mediaServerService.addToDatabase(mediaConfig.getMediaSerItem());
-        }else {
-            MediaServerItem mediaSerItem = mediaConfig.getMediaSerItem();
-            mediaServerService.updateToDatabase(mediaSerItem);
-        }
-        mediaServerService.syncCatchFromDatabase();
-        HookSubscribeForServerStarted hookSubscribeForServerStarted = HookSubscribeFactory.on_server_started();
-        // 璁㈤槄 zlm鍚姩浜嬩欢, 鏂扮殑zlm涔熶細浠庤繖閲岃繘鍏ョ郴缁�
-        hookSubscribe.addSubscribe(hookSubscribeForServerStarted,
-                (mediaServerItem, hookParam)->{
-            ZLMServerConfig zlmServerConfig = (ZLMServerConfig)hookParam;
-            if (zlmServerConfig !=null ) {
-                if (startGetMedia != null) {
-                    startGetMedia.remove(zlmServerConfig.getGeneralMediaServerId());
-                    if (startGetMedia.size() == 0) {
-                        hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started());
-                    }
-                }
-            }
-        });
-
-        // 鑾峰彇zlm淇℃伅
-        logger.info("[zlm] 绛夊緟榛樿zlm涓�...");
-
-        // 鑾峰彇鎵�鏈夌殑zlm锛� 骞跺紑鍚富鍔ㄨ繛鎺�
-        List<MediaServerItem> all = mediaServerService.getAllFromDatabase();
-        Map<String, MediaServerItem> allMap = new HashMap<>();
-        mediaServerService.updateVmServer(all);
-        if (all.size() == 0) {
-            all.add(mediaConfig.getMediaSerItem());
-        }
-        for (MediaServerItem mediaServerItem : all) {
-            if (startGetMedia == null) {
-                startGetMedia = new ConcurrentHashMap<>();
-            }
-            startGetMedia.put(mediaServerItem.getId(), true);
-            connectZlmServer(mediaServerItem);
-            allMap.put(mediaServerItem.getId(), mediaServerItem);
-        }
-        String taskKey = "zlm-connect-timeout";
-        dynamicTask.startDelay(taskKey, ()->{
-            if (startGetMedia != null && startGetMedia.size() > 0) {
-                Set<String> allZlmId = startGetMedia.keySet();
-                for (String id : allZlmId) {
-                    logger.error("[ {} ]]涓诲姩杩炴帴澶辫触锛屼笉鍐嶅皾璇曡繛鎺�", id);
-                }
-                startGetMedia = null;
-            }
-            // 鑾峰彇redis涓墍鏈夌殑zlm
-            List<MediaServerItem> allInRedis = mediaServerService.getAll();
-            for (MediaServerItem mediaServerItem : allInRedis) {
-                if (!allMap.containsKey(mediaServerItem.getId())) {
-                    mediaServerService.delete(mediaServerItem.getId());
-                }
-            }
-        }, 60 * 1000 );
-    }
-
-    @Async("taskExecutor")
-    public void connectZlmServer(MediaServerItem mediaServerItem){
-        String connectZlmServerTaskKey = "connect-zlm-" + mediaServerItem.getId();
-        ZLMServerConfig zlmServerConfigFirst = getMediaServerConfig(mediaServerItem);
-        if (zlmServerConfigFirst != null) {
-            zlmServerConfigFirst.setIp(mediaServerItem.getIp());
-            zlmServerConfigFirst.setHttpPort(mediaServerItem.getHttpPort());
-            startGetMedia.remove(mediaServerItem.getId());
-            if (startGetMedia.size() == 0) {
-                hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started());
-            }
-            mediaServerService.zlmServerOnline(zlmServerConfigFirst);
-        }else {
-            logger.info("[ {} ]-[ {}:{} ]涓诲姩杩炴帴澶辫触, 娓呯悊鐩稿叧璧勬簮锛� 寮�濮嬪皾璇曢噸璇曡繛鎺�",
-                    mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
-            publisher.zlmOfflineEventPublish(mediaServerItem.getId());
-        }
-
-        dynamicTask.startCron(connectZlmServerTaskKey, ()->{
-            ZLMServerConfig zlmServerConfig = getMediaServerConfig(mediaServerItem);
-            if (zlmServerConfig != null) {
-                dynamicTask.stop(connectZlmServerTaskKey);
-                zlmServerConfig.setIp(mediaServerItem.getIp());
-                zlmServerConfig.setHttpPort(mediaServerItem.getHttpPort());
-                startGetMedia.remove(mediaServerItem.getId());
-                if (startGetMedia.size() == 0) {
-                    hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started());
-                }
-                mediaServerService.zlmServerOnline(zlmServerConfig);
-            }
-        }, 2000);
-    }
-
-    public ZLMServerConfig getMediaServerConfig(MediaServerItem mediaServerItem) {
-        if (startGetMedia == null) { return null;}
-        if (!mediaServerItem.isDefaultServer() && mediaServerService.getOne(mediaServerItem.getId()) == null) {
-            return null;
-        }
-        if ( startGetMedia.get(mediaServerItem.getId()) == null || !startGetMedia.get(mediaServerItem.getId())) {
-            return null;
-        }
-        JSONObject responseJson = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
-        ZLMServerConfig zlmServerConfig = null;
-        if (responseJson != null) {
-            JSONArray data = responseJson.getJSONArray("data");
-            if (data != null && data.size() > 0) {
-                zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
-            }
-        } else {
-            logger.error("[ {} ]-[ {}:{} ]涓诲姩杩炴帴澶辫触, 2s鍚庨噸璇�",
-                    mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
-        }
-        return zlmServerConfig;
-
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java
index 027e990..14025ce 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java
@@ -5,7 +5,8 @@
 import com.genersoft.iot.vmp.common.CommonCallback;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -17,7 +18,7 @@
 @Component
 public class ZLMServerFactory {
 
-    private Logger logger = LoggerFactory.getLogger("ZLMRTPServerFactory");
+    private Logger logger = LoggerFactory.getLogger("ZLMServerFactory");
 
     @Autowired
     private ZLMRESTfulUtils zlmresTfulUtils;
@@ -26,7 +27,7 @@
     private UserSetting userSetting;
 
     @Autowired
-    private ZlmHttpHookSubscribe hookSubscribe;
+    private HookSubscribe hookSubscribe;
 
     @Autowired
     private SendRtpPortManager sendRtpPortManager;
@@ -42,7 +43,7 @@
      * @param tcpMode 0/null udp 妯″紡锛�1 tcp 琚姩妯″紡, 2 tcp 涓诲姩妯″紡銆�
      * @return
      */
-    public int createRTPServer(MediaServerItem mediaServerItem, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode) {
+    public int createRTPServer(MediaServer mediaServerItem, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode) {
         int result = -1;
         // 鏌ヨ姝tp server 鏄惁宸茬粡瀛樺湪
         JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId);
@@ -108,7 +109,7 @@
         return result;
     }
 
-    public boolean closeRtpServer(MediaServerItem serverItem, String streamId) {
+    public boolean closeRtpServer(MediaServer serverItem, String streamId) {
         boolean result = false;
         if (serverItem !=null){
             Map<String, Object> param = new HashMap<>();
@@ -129,7 +130,7 @@
         return result;
     }
 
-    public void closeRtpServer(MediaServerItem serverItem, String streamId, CommonCallback<Boolean> callback) {
+    public void closeRtpServer(MediaServer serverItem, String streamId, CommonCallback<Boolean> callback) {
         if (serverItem == null) {
             callback.run(false);
             return;
@@ -165,7 +166,7 @@
      * @param tcp 鏄惁涓簍cp
      * @return SendRtpItem
      */
-    public SendRtpItem createSendRtpItem(MediaServerItem serverItem, String ip, int port, String ssrc, String platformId,
+    public SendRtpItem createSendRtpItem(MediaServer serverItem, String ip, int port, String ssrc, String platformId,
                                          String deviceId, String channelId, boolean tcp, boolean rtcp){
 
         int localPort = sendRtpPortManager.getNextPort(serverItem);
@@ -198,7 +199,7 @@
      * @param tcp 鏄惁涓簍cp
      * @return SendRtpItem
      */
-    public SendRtpItem createSendRtpItem(MediaServerItem serverItem, String ip, int port, String ssrc, String platformId,
+    public SendRtpItem createSendRtpItem(MediaServer serverItem, String ip, int port, String ssrc, String platformId,
                                          String app, String stream, String channelId, boolean tcp, boolean rtcp){
 
         int localPort = sendRtpPortManager.getNextPort(serverItem);
@@ -224,25 +225,25 @@
     /**
      * 璋冪敤zlm RESTFUL API 鈥斺�� startSendRtp
      */
-    public JSONObject startSendRtpStream(MediaServerItem mediaServerItem, Map<String, Object>param) {
+    public JSONObject startSendRtpStream(MediaServer mediaServerItem, Map<String, Object>param) {
         return zlmresTfulUtils.startSendRtp(mediaServerItem, param);
     }
 
     /**
      * 璋冪敤zlm RESTFUL API 鈥斺�� startSendRtpPassive
      */
-    public JSONObject startSendRtpPassive(MediaServerItem mediaServerItem, Map<String, Object>param) {
+    public JSONObject startSendRtpPassive(MediaServer mediaServerItem, Map<String, Object>param) {
         return zlmresTfulUtils.startSendRtpPassive(mediaServerItem, param);
     }
 
-    public JSONObject startSendRtpPassive(MediaServerItem mediaServerItem, Map<String, Object>param, ZLMRESTfulUtils.RequestCallback callback) {
+    public JSONObject startSendRtpPassive(MediaServer mediaServerItem, Map<String, Object>param, ZLMRESTfulUtils.RequestCallback callback) {
         return zlmresTfulUtils.startSendRtpPassive(mediaServerItem, param, callback);
     }
 
     /**
      * 鏌ヨ寰呰浆鎺ㄧ殑娴佹槸鍚﹀氨缁�
      */
-    public Boolean isRtpReady(MediaServerItem mediaServerItem, String streamId) {
+    public Boolean isRtpReady(MediaServer mediaServerItem, String streamId) {
         JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtsp", streamId);
         if (mediaInfo.getInteger("code") == -2) {
             return null;
@@ -253,7 +254,7 @@
     /**
      * 鏌ヨ寰呰浆鎺ㄧ殑娴佹槸鍚﹀氨缁�
      */
-    public Boolean isStreamReady(MediaServerItem mediaServerItem, String app, String streamId) {
+    public Boolean isStreamReady(MediaServer mediaServerItem, String app, String streamId) {
         JSONObject mediaInfo = zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId);
         if (mediaInfo == null || (mediaInfo.getInteger("code") == -2)) {
             return null;
@@ -268,7 +269,7 @@
      * @param streamId
      * @return
      */
-    public int totalReaderCount(MediaServerItem mediaServerItem, String app, String streamId) {
+    public int totalReaderCount(MediaServer mediaServerItem, String app, String streamId) {
         JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtsp", streamId);
         if (mediaInfo == null) {
             return 0;
@@ -288,7 +289,7 @@
     /**
      * 璋冪敤zlm RESTful API 鈥斺�� stopSendRtp
      */
-    public Boolean stopSendRtpStream(MediaServerItem mediaServerItem, Map<String, Object>param) {
+    public Boolean stopSendRtpStream(MediaServer mediaServerItem, Map<String, Object>param) {
         if (mediaServerItem == null) {
             logger.error("[鍋滄RTP鎺ㄦ祦] 澶辫触: 濯掍綋鑺傜偣涓篘ULL");
             return false;
@@ -306,7 +307,7 @@
         return result;
     }
 
-    public JSONObject startSendRtp(MediaServerItem mediaInfo, SendRtpItem sendRtpItem) {
+    public JSONObject startSendRtp(MediaServer mediaInfo, SendRtpItem sendRtpItem) {
         String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
         logger.info("rtp/{}寮�濮嬫帹娴�, 鐩爣={}:{}锛孲SRC={}", sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
         Map<String, Object> param = new HashMap<>(12);
@@ -351,7 +352,7 @@
         return startSendRtpStreamResult;
     }
 
-    public Boolean updateRtpServerSSRC(MediaServerItem mediaServerItem, String streamId, String ssrc) {
+    public Boolean updateRtpServerSSRC(MediaServer mediaServerItem, String streamId, String ssrc) {
         boolean result = false;
         JSONObject jsonObject = zlmresTfulUtils.updateRtpServerSSRC(mediaServerItem, streamId, ssrc);
         if (jsonObject == null) {
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java
deleted file mode 100755
index 5e46f55..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm;
-
-import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.media.zlm.dto.HookType;
-import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-import org.springframework.util.CollectionUtils;
-
-import java.time.Instant;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-
-/**
- * ZLMediaServer鐨刪ook浜嬩欢璁㈤槄
- * @author lin
- */
-@Component
-public class ZlmHttpHookSubscribe {
-
-    private final static Logger logger = LoggerFactory.getLogger(ZlmHttpHookSubscribe.class);
-
-    @FunctionalInterface
-    public interface Event{
-        void response(MediaServerItem mediaServerItem, HookParam hookParam);
-    }
-
-    private Map<HookType, Map<IHookSubscribe, ZlmHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
-
-    public void addSubscribe(IHookSubscribe hookSubscribe, ZlmHttpHookSubscribe.Event event) {
-        if (hookSubscribe.getExpires() == null) {
-            // 榛樿5鍒嗛挓杩囨湡
-            Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.MINUTES.toSeconds(5));
-            hookSubscribe.setExpires(expiresInstant);
-        }
-        allSubscribes.computeIfAbsent(hookSubscribe.getHookType(), k -> new ConcurrentHashMap<>()).put(hookSubscribe, event);
-        System.out.println(allSubscribes);
-    }
-
-    public ZlmHttpHookSubscribe.Event sendNotify(HookType type, JSONObject hookResponse) {
-        ZlmHttpHookSubscribe.Event event= null;
-        Map<IHookSubscribe, Event> eventMap = allSubscribes.get(type);
-        if (eventMap == null) {
-            return null;
-        }
-        for (IHookSubscribe key : eventMap.keySet()) {
-            Boolean result = null;
-
-            for (String s : key.getContent().keySet()) {
-                if (result == null) {
-                    result = key.getContent().getString(s).equals(hookResponse.getString(s));
-                }else {
-                    if (key.getContent().getString(s) == null) {
-                        continue;
-                    }
-                    result = result && key.getContent().getString(s).equals(hookResponse.getString(s));
-                }
-            }
-            if (null != result && result) {
-                event = eventMap.get(key);
-            }
-        }
-        return event;
-    }
-
-    public void removeSubscribe(IHookSubscribe hookSubscribe) {
-        Map<IHookSubscribe, Event> eventMap = allSubscribes.get(hookSubscribe.getHookType());
-        if (eventMap == null) {
-            return;
-        }
-
-        Set<Map.Entry<IHookSubscribe, Event>> entries = eventMap.entrySet();
-        if (entries.size() > 0) {
-            List<Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event>> entriesToRemove = new ArrayList<>();
-            for (Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event> entry : entries) {
-                JSONObject content = entry.getKey().getContent();
-                if (content == null || content.size() == 0) {
-                    entriesToRemove.add(entry);
-                    continue;
-                }
-                Boolean result = null;
-                for (String s : content.keySet()) {
-                    if (result == null) {
-                        result = content.getString(s).equals(hookSubscribe.getContent().getString(s));
-                    }else {
-                        if (content.getString(s) == null) {
-                            continue;
-                        }
-                        result = result && content.getString(s).equals(hookSubscribe.getContent().getString(s));
-                    }
-                }
-                if (result){
-                    entriesToRemove.add(entry);
-                }
-            }
-
-            if (!CollectionUtils.isEmpty(entriesToRemove)) {
-                for (Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event> entry : entriesToRemove) {
-                    eventMap.remove(entry.getKey());
-                }
-                if (eventMap.size() == 0) {
-                    allSubscribes.remove(hookSubscribe.getHookType());
-                }
-            }
-
-        }
-    }
-
-    /**
-     * 鑾峰彇鏌愪釜绫诲瀷鐨勬墍鏈夌殑璁㈤槄
-     * @param type
-     * @return
-     */
-    public List<ZlmHttpHookSubscribe.Event> getSubscribes(HookType type) {
-        Map<IHookSubscribe, Event> eventMap = allSubscribes.get(type);
-        if (eventMap == null) {
-            return null;
-        }
-        List<ZlmHttpHookSubscribe.Event> result = new ArrayList<>();
-        for (IHookSubscribe key : eventMap.keySet()) {
-            result.add(eventMap.get(key));
-        }
-        return result;
-    }
-
-    public List<IHookSubscribe> getAll(){
-        ArrayList<IHookSubscribe> result = new ArrayList<>();
-        Collection<Map<IHookSubscribe, Event>> values = allSubscribes.values();
-        for (Map<IHookSubscribe, Event> value : values) {
-            result.addAll(value.keySet());
-        }
-        return result;
-    }
-
-    /**
-     * 瀵硅闃呮暟鎹繘琛岃繃鏈熸竻鐞�
-     */
-//    @Scheduled(cron="0 0/5 * * * ?")   //姣�5鍒嗛挓鎵ц涓�娆�
-    @Scheduled(fixedRate = 2 * 1000)
-    public void execute(){
-        Instant instant = Instant.now().minusMillis(TimeUnit.MINUTES.toMillis(5));
-        int total = 0;
-        for (HookType hookType : allSubscribes.keySet()) {
-            Map<IHookSubscribe, Event> hookSubscribeEventMap = allSubscribes.get(hookType);
-            if (hookSubscribeEventMap.size() > 0) {
-                for (IHookSubscribe hookSubscribe : hookSubscribeEventMap.keySet()) {
-                    if (hookSubscribe.getExpires().isBefore(instant)) {
-                        // 杩囨湡鐨�
-                        hookSubscribeEventMap.remove(hookSubscribe);
-                        total ++;
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java
deleted file mode 100755
index f828bdd..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm.dto;
-
-
-import com.alibaba.fastjson2.JSONObject;
-
-/**
- * hook 璁㈤槄宸ュ巶
- * @author lin
- */
-public class HookSubscribeFactory {
-
-    public static HookSubscribeForStreamChange on_stream_changed(String app, String stream, boolean regist, String scheam, String mediaServerId) {
-        HookSubscribeForStreamChange hookSubscribe = new HookSubscribeForStreamChange();
-        JSONObject subscribeKey = new com.alibaba.fastjson2.JSONObject();
-        subscribeKey.put("app", app);
-        subscribeKey.put("stream", stream);
-        subscribeKey.put("regist", regist);
-        if (scheam != null) {
-            subscribeKey.put("schema", scheam);
-        }
-        subscribeKey.put("mediaServerId", mediaServerId);
-        hookSubscribe.setContent(subscribeKey);
-
-        return hookSubscribe;
-    }
-
-    public static HookSubscribeForRtpServerTimeout on_rtp_server_timeout(String stream, String ssrc, String mediaServerId) {
-        HookSubscribeForRtpServerTimeout hookSubscribe = new HookSubscribeForRtpServerTimeout();
-        JSONObject subscribeKey = new com.alibaba.fastjson2.JSONObject();
-        subscribeKey.put("stream_id", stream);
-        subscribeKey.put("ssrc", ssrc);
-        subscribeKey.put("mediaServerId", mediaServerId);
-        hookSubscribe.setContent(subscribeKey);
-
-        return hookSubscribe;
-    }
-
-    public static HookSubscribeForStreamPush on_publish(String app, String stream, String scheam, String mediaServerId) {
-        HookSubscribeForStreamPush hookSubscribe = new HookSubscribeForStreamPush();
-        JSONObject subscribeKey = new JSONObject();
-        subscribeKey.put("app", app);
-        subscribeKey.put("stream", stream);
-        if (scheam != null) {
-            subscribeKey.put("schema", scheam);
-        }
-        subscribeKey.put("mediaServerId", mediaServerId);
-        hookSubscribe.setContent(subscribeKey);
-
-        return hookSubscribe;
-    }
-
-
-    public static HookSubscribeForServerStarted on_server_started() {
-        HookSubscribeForServerStarted hookSubscribe = new HookSubscribeForServerStarted();
-        hookSubscribe.setContent(new JSONObject());
-
-        return hookSubscribe;
-    }
-
-    public static HookSubscribeForRecordMp4 on_record_mp4(String mediaServerId, String app, String stream) {
-        HookSubscribeForRecordMp4 hookSubscribe = new HookSubscribeForRecordMp4();
-        JSONObject subscribeKey = new com.alibaba.fastjson2.JSONObject();
-        subscribeKey.put("app", app);
-        subscribeKey.put("stream", stream);
-        subscribeKey.put("mediaServerId", mediaServerId);
-        hookSubscribe.setContent(subscribeKey);
-
-        return hookSubscribe;
-    }
-
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRecordMp4.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRecordMp4.java
deleted file mode 100755
index 34c467c..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRecordMp4.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm.dto;
-
-import com.alibaba.fastjson2.JSONObject;
-import com.alibaba.fastjson2.annotation.JSONField;
-
-import java.time.Instant;
-
-/**
- * hook璁㈤槄-褰曞儚瀹屾垚
- * @author lin
- */
-public class HookSubscribeForRecordMp4 implements IHookSubscribe{
-
-    private HookType hookType = HookType.on_record_mp4;
-
-    private JSONObject content;
-
-    @JSONField(format="yyyy-MM-dd HH:mm:ss")
-    private Instant expires;
-
-    @Override
-    public HookType getHookType() {
-        return hookType;
-    }
-
-    @Override
-    public JSONObject getContent() {
-        return content;
-    }
-
-    public void setContent(JSONObject content) {
-        this.content = content;
-    }
-
-    @Override
-    public Instant getExpires() {
-        return expires;
-    }
-
-    @Override
-    public void setExpires(Instant expires) {
-        this.expires = expires;
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRtpServerTimeout.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRtpServerTimeout.java
deleted file mode 100755
index d633560..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRtpServerTimeout.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm.dto;
-
-import com.alibaba.fastjson2.JSONObject;
-import com.alibaba.fastjson2.annotation.JSONField;
-
-import java.time.Instant;
-
-/**
- * hook璁㈤槄-鏀舵祦瓒呮椂
- * @author lin
- */
-public class HookSubscribeForRtpServerTimeout implements IHookSubscribe{
-
-    private HookType hookType = HookType.on_rtp_server_timeout;
-
-    private JSONObject content;
-
-    @JSONField(format="yyyy-MM-dd HH:mm:ss")
-    private Instant expires;
-
-    @Override
-    public HookType getHookType() {
-        return hookType;
-    }
-
-    @Override
-    public JSONObject getContent() {
-        return content;
-    }
-
-    public void setContent(JSONObject content) {
-        this.content = content;
-    }
-
-    @Override
-    public Instant getExpires() {
-        return expires;
-    }
-
-    @Override
-    public void setExpires(Instant expires) {
-        this.expires = expires;
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForServerStarted.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForServerStarted.java
deleted file mode 100755
index 8bcde0a..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForServerStarted.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm.dto;
-
-import com.alibaba.fastjson2.JSONObject;
-import com.alibaba.fastjson2.annotation.JSONField;
-
-import java.time.Instant;
-
-/**
- * hook璁㈤槄-娴佸彉鍖�
- * @author lin
- */
-public class HookSubscribeForServerStarted implements IHookSubscribe{
-
-    private HookType hookType = HookType.on_server_started;
-
-    private JSONObject content;
-
-    @JSONField(format="yyyy-MM-dd HH:mm:ss")
-    private Instant expires;
-
-    @Override
-    public HookType getHookType() {
-        return hookType;
-    }
-
-    @Override
-    public JSONObject getContent() {
-        return content;
-    }
-
-    public void setContent(JSONObject content) {
-        this.content = content;
-    }
-
-    @Override
-    public Instant getExpires() {
-        return expires;
-    }
-
-    @Override
-    public void setExpires(Instant expires) {
-        this.expires = expires;
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamChange.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamChange.java
deleted file mode 100755
index b73d74c..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamChange.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm.dto;
-
-import com.alibaba.fastjson2.JSONObject;
-import com.alibaba.fastjson2.annotation.JSONField;
-
-import java.time.Instant;
-
-/**
- * hook璁㈤槄-娴佸彉鍖�
- * @author lin
- */
-public class HookSubscribeForStreamChange implements IHookSubscribe{
-
-    private HookType hookType = HookType.on_stream_changed;
-
-    private JSONObject content;
-
-    @JSONField(format="yyyy-MM-dd HH:mm:ss")
-    private Instant expires;
-
-    @Override
-    public HookType getHookType() {
-        return hookType;
-    }
-
-    @Override
-    public JSONObject getContent() {
-        return content;
-    }
-
-    public void setContent(JSONObject content) {
-        this.content = content;
-    }
-
-    @Override
-    public Instant getExpires() {
-        return expires;
-    }
-
-    @Override
-    public void setExpires(Instant expires) {
-        this.expires = expires;
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamPush.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamPush.java
deleted file mode 100644
index 6418134..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamPush.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm.dto;
-
-
-import com.alibaba.fastjson2.JSONObject;
-
-import java.time.Instant;
-
-/**
- * hook璁㈤槄-寮�濮嬫帹娴�
- * @author lin
- */
-public class HookSubscribeForStreamPush implements IHookSubscribe{
-
-    private HookType hookType = HookType.on_publish;
-
-    private JSONObject content;
-
-    private Instant expires;
-
-    @Override
-    public HookType getHookType() {
-        return hookType;
-    }
-
-    @Override
-    public JSONObject getContent() {
-        return content;
-    }
-
-    public void setContent(JSONObject content) {
-        this.content = content;
-    }
-
-    @Override
-    public Instant getExpires() {
-        return expires;
-    }
-
-    @Override
-    public void setExpires(Instant expires) {
-        this.expires = expires;
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookType.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookType.java
deleted file mode 100755
index 235cea7..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookType.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm.dto;
-
-/**
- * hook绫诲瀷
- * @author lin
- */
-
-public enum HookType {
-
-    on_flow_report,
-    on_http_access,
-    on_play,
-    on_publish,
-    on_record_mp4,
-    on_rtsp_auth,
-    on_rtsp_realm,
-    on_shell_login,
-    on_stream_changed,
-    on_stream_none_reader,
-    on_stream_not_found,
-    on_server_started,
-
-    on_rtp_server_timeout,
-    on_server_keepalive,
-    on_send_rtp_stopped
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IHookSubscribe.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IHookSubscribe.java
deleted file mode 100755
index 7b76a95..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IHookSubscribe.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm.dto;
-
-import com.alibaba.fastjson2.JSONObject;
-
-import java.time.Instant;
-
-/**
- * zlm hook浜嬩欢鐨勫弬鏁�
- * @author lin
- */
-public interface IHookSubscribe {
-
-    /**
-     * 鑾峰彇hook绫诲瀷
-     * @return hook绫诲瀷
-     */
-    HookType getHookType();
-
-    /**
-     * 鑾峰彇hook鐨勫叿浣撳唴瀹�
-     * @return hook鐨勫叿浣撳唴瀹�
-     */
-    JSONObject getContent();
-
-    /**
-     * 璁剧疆杩囨湡鏃堕棿
-     * @param instant 杩囨湡鏃堕棿
-     */
-    void setExpires(Instant instant);
-
-    /**
-     * 鑾峰彇杩囨湡鏃堕棿
-     * @return 杩囨湡鏃堕棿
-     */
-    Instant getExpires();
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItemLite.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItemLite.java
deleted file mode 100644
index 4e0ffe9..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItemLite.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm.dto;
-
-
-/**
- * 绮剧畝鐨凪ediaServerItem淇℃伅锛屾柟渚跨粰鍓嶇杩斿洖鏁版嵁
- */
-public class MediaServerItemLite {
-
-    private String id;
-
-    private String ip;
-
-    private String hookIp;
-
-    private String sdpIp;
-
-    private String streamIp;
-
-    private int httpPort;
-
-    private int httpSSlPort;
-
-    private int rtmpPort;
-
-    private int rtmpSSlPort;
-
-    private int rtpProxyPort;
-
-    private int rtspPort;
-
-    private int rtspSSLPort;
-
-    private String secret;
-
-    private int recordAssistPort;
-
-
-
-    public MediaServerItemLite(MediaServerItem mediaServerItem) {
-        this.id = mediaServerItem.getId();
-        this.ip = mediaServerItem.getIp();
-        this.hookIp = mediaServerItem.getHookIp();
-        this.sdpIp = mediaServerItem.getSdpIp();
-        this.streamIp = mediaServerItem.getStreamIp();
-        this.httpPort = mediaServerItem.getHttpPort();
-        this.httpSSlPort = mediaServerItem.getHttpSSlPort();
-        this.rtmpPort = mediaServerItem.getRtmpPort();
-        this.rtmpSSlPort = mediaServerItem.getRtmpSSlPort();
-        this.rtpProxyPort = mediaServerItem.getRtpProxyPort();
-        this.rtspPort = mediaServerItem.getRtspPort();
-        this.rtspSSLPort = mediaServerItem.getRtspSSLPort();
-        this.secret = mediaServerItem.getSecret();
-        this.recordAssistPort = mediaServerItem.getRecordAssistPort();
-    }
-
-    public String getId() {
-        return id;
-    }
-
-    public void setId(String id) {
-        this.id = id;
-    }
-
-    public String getIp() {
-        return ip;
-    }
-
-    public void setIp(String ip) {
-        this.ip = ip;
-    }
-
-    public String getHookIp() {
-        return hookIp;
-    }
-
-    public void setHookIp(String hookIp) {
-        this.hookIp = hookIp;
-    }
-
-    public String getSdpIp() {
-        return sdpIp;
-    }
-
-    public void setSdpIp(String sdpIp) {
-        this.sdpIp = sdpIp;
-    }
-
-    public String getStreamIp() {
-        return streamIp;
-    }
-
-    public void setStreamIp(String streamIp) {
-        this.streamIp = streamIp;
-    }
-
-    public int getHttpPort() {
-        return httpPort;
-    }
-
-    public void setHttpPort(int httpPort) {
-        this.httpPort = httpPort;
-    }
-
-    public int getHttpSSlPort() {
-        return httpSSlPort;
-    }
-
-    public void setHttpSSlPort(int httpSSlPort) {
-        this.httpSSlPort = httpSSlPort;
-    }
-
-    public int getRtmpPort() {
-        return rtmpPort;
-    }
-
-    public void setRtmpPort(int rtmpPort) {
-        this.rtmpPort = rtmpPort;
-    }
-
-    public int getRtmpSSlPort() {
-        return rtmpSSlPort;
-    }
-
-    public void setRtmpSSlPort(int rtmpSSlPort) {
-        this.rtmpSSlPort = rtmpSSlPort;
-    }
-
-    public int getRtpProxyPort() {
-        return rtpProxyPort;
-    }
-
-    public void setRtpProxyPort(int rtpProxyPort) {
-        this.rtpProxyPort = rtpProxyPort;
-    }
-
-    public int getRtspPort() {
-        return rtspPort;
-    }
-
-    public void setRtspPort(int rtspPort) {
-        this.rtspPort = rtspPort;
-    }
-
-    public int getRtspSSLPort() {
-        return rtspSSLPort;
-    }
-
-    public void setRtspSSLPort(int rtspSSLPort) {
-        this.rtspSSLPort = rtspSSLPort;
-    }
-
-
-    public String getSecret() {
-        return secret;
-    }
-
-    public void setSecret(String secret) {
-        this.secret = secret;
-    }
-
-    public int getRecordAssistPort() {
-        return recordAssistPort;
-    }
-
-    public void setRecordAssistPort(int recordAssistPort) {
-        this.recordAssistPort = recordAssistPort;
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamAuthorityInfo.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamAuthorityInfo.java
index ef77225..8b722a9 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamAuthorityInfo.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamAuthorityInfo.java
@@ -1,7 +1,6 @@
 package com.genersoft.iot.vmp.media.zlm.dto;
 
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnPublishHookParam;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
+import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
 
 /**
  * 娴佺殑閴存潈淇℃伅
@@ -97,21 +96,23 @@
         this.sign = sign;
     }
 
-    public static StreamAuthorityInfo getInstanceByHook(OnPublishHookParam hookParam) {
+    public static StreamAuthorityInfo getInstanceByHook(String app, String stream, String id) {
         StreamAuthorityInfo streamAuthorityInfo = new StreamAuthorityInfo();
-        streamAuthorityInfo.setApp(hookParam.getApp());
-        streamAuthorityInfo.setStream(hookParam.getStream());
-        streamAuthorityInfo.setId(hookParam.getId());
+        streamAuthorityInfo.setApp(app);
+        streamAuthorityInfo.setStream(stream);
+        streamAuthorityInfo.setId(id);
         return streamAuthorityInfo;
     }
 
-    public static StreamAuthorityInfo getInstanceByHook(OnStreamChangedHookParam onStreamChangedHookParam) {
+    public static StreamAuthorityInfo getInstanceByHook(MediaArrivalEvent event) {
         StreamAuthorityInfo streamAuthorityInfo = new StreamAuthorityInfo();
-        streamAuthorityInfo.setApp(onStreamChangedHookParam.getApp());
-        streamAuthorityInfo.setStream(onStreamChangedHookParam.getStream());
-        streamAuthorityInfo.setId(onStreamChangedHookParam.getMediaServerId());
-        streamAuthorityInfo.setOriginType(onStreamChangedHookParam.getOriginType());
-        streamAuthorityInfo.setOriginTypeStr(onStreamChangedHookParam.getOriginTypeStr());
+        streamAuthorityInfo.setApp(event.getApp());
+        streamAuthorityInfo.setStream(event.getStream());
+        streamAuthorityInfo.setId(event.getMediaServer().getId());
+        if (event.getMediaInfo() != null) {
+            streamAuthorityInfo.setOriginType(event.getMediaInfo().getOriginType());
+        }
+
         return streamAuthorityInfo;
     }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java
index 6befe46..797286f 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java
@@ -1,6 +1,8 @@
 package com.genersoft.iot.vmp.media.zlm.dto;
 
+import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
+import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -150,6 +152,47 @@
                 - DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(streamPushItem.getCreateTime())).intValue();
     }
 
+    public StreamPushItem getInstance(StreamInfo streamInfo) {
+        StreamPushItem streamPushItem = new StreamPushItem();
+        streamPushItem.setApp(streamInfo.getApp());
+        streamPushItem.setMediaServerId(streamInfo.getMediaServerId());
+        streamPushItem.setStream(streamInfo.getStream());
+        streamPushItem.setAliveSecond(streamInfo.getMediaInfo().getAliveSecond());
+//        streamPushItem.setOriginSock(streamInfo.getMediaInfo().getOriginSock());
+        streamPushItem.setTotalReaderCount(streamInfo.getMediaInfo().getReaderCount() + "");
+        streamPushItem.setOriginType(streamInfo.getOriginType());
+//        streamPushItem.setOriginTypeStr(streamInfo.getMediaInfo().getOriginTypeStr());
+//        streamPushItem.setOriginUrl(streamInfo.getMediaInfo().getOriginUrl());
+        streamPushItem.setCreateTime(DateUtil.getNow());
+        streamPushItem.setAliveSecond(streamInfo.getMediaInfo().getAliveSecond());
+        streamPushItem.setStatus(true);
+        streamPushItem.setStreamType("push");
+//        streamPushItem.setVhost(streamInfo.getVhost());
+        streamPushItem.setServerId(streamInfo.getMediaServerId());
+        return streamPushItem;
+
+    }
+
+    public static StreamPushItem getInstance(MediaArrivalEvent event, String serverId){
+        StreamPushItem streamPushItem = new StreamPushItem();
+        streamPushItem.setApp(event.getApp());
+        streamPushItem.setMediaServerId(event.getMediaServer().getId());
+        streamPushItem.setStream(event.getStream());
+        streamPushItem.setAliveSecond(event.getMediaInfo().getAliveSecond());
+//        streamPushItem.setOriginSock(streamInfo.getMediaInfo().getOriginSock());
+        streamPushItem.setTotalReaderCount(event.getMediaInfo().getReaderCount() + "");
+        streamPushItem.setOriginType(event.getMediaInfo().getOriginType());
+//        streamPushItem.setOriginTypeStr(streamInfo.getMediaInfo().getOriginTypeStr());
+//        streamPushItem.setOriginUrl(streamInfo.getMediaInfo().getOriginUrl());
+        streamPushItem.setCreateTime(DateUtil.getNow());
+        streamPushItem.setAliveSecond(event.getMediaInfo().getAliveSecond());
+        streamPushItem.setStatus(true);
+        streamPushItem.setStreamType("push");
+//        streamPushItem.setVhost(streamInfo.getVhost());
+        streamPushItem.setServerId(serverId);
+        return streamPushItem;
+    }
+
     public static class MediaSchema {
         private String schema;
         private Long bytesSpeed;
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java
similarity index 99%
rename from src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
rename to src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java
index 80910c0..8f77b63 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java
@@ -1,4 +1,4 @@
-package com.genersoft.iot.vmp.media.zlm;
+package com.genersoft.iot.vmp.media.zlm.dto;
 
 import com.alibaba.fastjson2.annotation.JSONField;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookParam.java
index 46ccf22..ae3bd68 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookParam.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookParam.java
@@ -7,6 +7,8 @@
 public class HookParam {
     private String mediaServerId;
 
+
+
     public String getMediaServerId() {
         return mediaServerId;
     }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java
index b327f13..dee9d66 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java
@@ -18,8 +18,8 @@
         return new HookResult(0, "success");
     }
 
-    public static HookResult Fail(){
-        return new HookResult(-1, "fail");
+    public static HookResultForOnPublish Fail(){
+        return new HookResultForOnPublish(-1, "fail");
     }
 
     public int getCode() {
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
index 55369e5..33f9856 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
@@ -1,5 +1,7 @@
 package com.genersoft.iot.vmp.media.zlm.dto.hook;
 
+import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
+
 public class HookResultForOnPublish extends HookResult{
 
     private boolean enable_audio;
@@ -16,6 +18,17 @@
         return new HookResultForOnPublish(0, "success");
     }
 
+    public static HookResultForOnPublish getInstance(ResultForOnPublish resultForOnPublish){
+        HookResultForOnPublish successResult = new HookResultForOnPublish(0, "success");
+        successResult.setEnable_audio(resultForOnPublish.isEnable_audio());
+        successResult.setEnable_mp4(resultForOnPublish.isEnable_mp4());
+        successResult.setModify_stamp(resultForOnPublish.getModify_stamp());
+        successResult.setStream_replace(resultForOnPublish.getStream_replace());
+        successResult.setMp4_max_second(resultForOnPublish.getMp4_max_second());
+        successResult.setMp4_save_path(resultForOnPublish.getMp4_save_path());
+        return successResult;
+    }
+
     public HookResultForOnPublish(int code, String msg) {
         setCode(code);
         setMsg(msg);
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
index ffca0d5..efd1454 100755
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
@@ -32,7 +32,7 @@
     /**
      * 瑙傜湅鎬讳汉鏁帮紝鍖呮嫭hls/rtsp/rtmp/http-flv/ws-flv
      */
-    private String totalReaderCount;
+    private int totalReaderCount;
 
     /**
      * 鍗忚 鍖呮嫭hls/rtsp/rtmp/http-flv/ws-flv
@@ -374,11 +374,11 @@
         this.stream = stream;
     }
 
-    public String getTotalReaderCount() {
+    public int getTotalReaderCount() {
         return totalReaderCount;
     }
 
-    public void setTotalReaderCount(String totalReaderCount) {
+    public void setTotalReaderCount(int totalReaderCount) {
         this.totalReaderCount = totalReaderCount;
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/HookZlmServerKeepaliveEvent.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/HookZlmServerKeepaliveEvent.java
new file mode 100644
index 0000000..b927062
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/HookZlmServerKeepaliveEvent.java
@@ -0,0 +1,24 @@
+package com.genersoft.iot.vmp.media.zlm.event;
+
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * zlm 蹇冭烦浜嬩欢
+ */
+public class HookZlmServerKeepaliveEvent extends ApplicationEvent {
+
+    public HookZlmServerKeepaliveEvent(Object source) {
+        super(source);
+    }
+
+    private MediaServer mediaServerItem;
+
+    public MediaServer getMediaServerItem() {
+        return mediaServerItem;
+    }
+
+    public void setMediaServerItem(MediaServer mediaServerItem) {
+        this.mediaServerItem = mediaServerItem;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/HookZlmServerStartEvent.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/HookZlmServerStartEvent.java
new file mode 100644
index 0000000..e1c28b1
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/HookZlmServerStartEvent.java
@@ -0,0 +1,24 @@
+package com.genersoft.iot.vmp.media.zlm.event;
+
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * zlm server_start浜嬩欢
+ */
+public class HookZlmServerStartEvent extends ApplicationEvent {
+
+    public HookZlmServerStartEvent(Object source) {
+        super(source);
+    }
+
+    private MediaServer mediaServerItem;
+
+    public MediaServer getMediaServerItem() {
+        return mediaServerItem;
+    }
+
+    public void setMediaServerItem(MediaServer mediaServerItem) {
+        this.mediaServerItem = mediaServerItem;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOfflineEvent.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOfflineEvent.java
deleted file mode 100755
index 8207bdd..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOfflineEvent.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm.event;
-
-/**
- * zlm绂荤嚎浜嬩欢绫�
- */
-public class ZLMOfflineEvent extends ZLMEventAbstract {
-
-	public ZLMOfflineEvent(Object source) {
-		super(source);
-	}
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOnlineEvent.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOnlineEvent.java
deleted file mode 100755
index 612ff9d..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOnlineEvent.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm.event;
-
-/**
- * zlm鍦ㄧ嚎浜嬩欢
- */
-public class ZLMOnlineEvent extends ZLMEventAbstract {
-
-	public ZLMOnlineEvent(Object source) {
-		super(source);
-	}
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java b/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java
index c10313e..875140f 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java
@@ -1,8 +1,7 @@
 package com.genersoft.iot.vmp.service;
 
 import com.alibaba.fastjson2.JSONArray;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
 import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
 import com.github.pagehelper.PageInfo;
@@ -18,22 +17,17 @@
     /**
      * 鍒嗛〉鍥炲幓浜戠褰曞儚鍒楄〃
      */
-    PageInfo<CloudRecordItem> getList(int page, int count, String query,  String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems);
-
-    /**
-     * 鏍规嵁hook娑堟伅澧炲姞涓�鏉¤褰�
-     */
-    void addRecord(OnRecordMp4HookParam param);
+    PageInfo<CloudRecordItem> getList(int page, int count, String query,  String app, String stream, String startTime, String endTime, List<MediaServer> mediaServerItems);
 
     /**
      * 鑾峰彇鎵�鏈夌殑鏃ユ湡
      */
-    List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems);
+    List<String> getDateList(String app, String stream, int year, int month, List<MediaServer> mediaServerItems);
 
     /**
      * 娣诲姞鍚堝苟浠诲姟
      */
-    String addTask(String app, String stream, MediaServerItem mediaServerItem, String startTime,
+    String addTask(String app, String stream, MediaServer mediaServerItem, String startTime,
                    String endTime, String callId, String remoteHost, boolean filterMediaServer);
 
 
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
deleted file mode 100755
index 2e6151d..0000000
--- a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.genersoft.iot.vmp.service;
-
-import com.genersoft.iot.vmp.common.CommonCallback;
-import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData;
-import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
-import com.genersoft.iot.vmp.service.bean.SSRCInfo;
-import com.genersoft.iot.vmp.vmanager.bean.RecordFile;
-
-import java.util.List;
-
-/**
- * 濯掍綋鏈嶅姟鑺傜偣
- */
-public interface IMediaServerService {
-
-    List<MediaServerItem> getAll();
-
-    List<MediaServerItem> getAllFromDatabase();
-
-    List<MediaServerItem> getAllOnline();
-
-    MediaServerItem getOne(String generalMediaServerId);
-
-    void syncCatchFromDatabase();
-
-    /**
-     * 鏂扮殑鑺傜偣鍔犲叆
-     * @param zlmServerConfig
-     * @return
-     */
-    void zlmServerOnline(ZLMServerConfig zlmServerConfig);
-
-    /**
-     * 鑺傜偣绂荤嚎
-     * @param mediaServerId
-     * @return
-     */
-    void zlmServerOffline(String mediaServerId);
-
-    MediaServerItem getMediaServerForMinimumLoad(Boolean hasAssist);
-
-    void setZLMConfig(MediaServerItem mediaServerItem, boolean restart);
-
-    void updateVmServer(List<MediaServerItem>  mediaServerItemList);
-
-    SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck,
-                           boolean isPlayback, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode);
-
-    SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback, Integer port, Boolean onlyAuto);
-
-    void closeRTPServer(MediaServerItem mediaServerItem, String streamId);
-
-    void closeRTPServer(MediaServerItem mediaServerItem, String streamId, CommonCallback<Boolean> callback);
-    Boolean updateRtpServerSSRC(MediaServerItem mediaServerItem, String streamId, String ssrc);
-
-    void closeRTPServer(String mediaServerId, String streamId);
-
-    void clearRTPServer(MediaServerItem mediaServerItem);
-
-    void update(MediaServerItem mediaSerItem);
-
-    void addCount(String mediaServerId);
-
-    void removeCount(String mediaServerId);
-
-    void releaseSsrc(String mediaServerItemId, String ssrc);
-
-    void clearMediaServerForOnline();
-
-    void add(MediaServerItem mediaSerItem);
-
-    int addToDatabase(MediaServerItem mediaSerItem);
-
-    int updateToDatabase(MediaServerItem mediaSerItem);
-
-    void resetOnlineServerItem(MediaServerItem serverItem);
-
-    MediaServerItem checkMediaServer(String ip, int port, String secret);
-
-    boolean checkMediaRecordServer(String ip, int port);
-
-    void delete(String id);
-
-    void deleteDb(String id);
-
-    MediaServerItem getDefaultMediaServer();
-
-    void updateMediaServerKeepalive(String mediaServerId, ServerKeepaliveData data);
-
-    /**
-     * 鑾峰彇璐熻浇淇℃伅
-     * @return
-     */
-    MediaServerLoad getLoad(MediaServerItem mediaServerItem);
-
-    List<MediaServerItem> getAllWithAssistPort();
-
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IMediaService.java b/src/main/java/com/genersoft/iot/vmp/service/IMediaService.java
index 82de3bb..26f1585 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/IMediaService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IMediaService.java
@@ -1,8 +1,7 @@
 package com.genersoft.iot.vmp.service;
 
-import com.alibaba.fastjson2.JSONArray;
-import com.genersoft.iot.vmp.common.StreamInfo;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 
 /**
  * 濯掍綋淇℃伅涓氬姟
@@ -10,35 +9,11 @@
 public interface IMediaService {
 
     /**
-     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 閫氳繃zlm鎺ュ彛妫�鏌ユ槸鍚﹀瓨鍦�
-     * @param app
-     * @param stream
-     * @return
+     * 鎾斁閴存潈
      */
-    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId,String addr, boolean authority);
+    boolean authenticatePlay(String app, String stream, String callId);
 
+    ResultForOnPublish authenticatePublish(MediaServer mediaServer, String app, String stream, String params);
 
-    /**
-     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 閫氳繃zlm鎺ュ彛妫�鏌ユ槸鍚﹀瓨鍦�, 杩斿洖鐨刬p浣跨敤杩滅▼璁块棶ip锛岄�傜敤涓巣lm涓巜vp鍦ㄤ竴鍙颁富鏈虹殑鎯呭喌
-     * @param app
-     * @param stream
-     * @return
-     */
-    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, boolean authority);
-
-    /**
-     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 鍙槸鍦板潃鎷兼帴
-     * @param app
-     * @param stream
-     * @return
-     */
-    StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaServerItem, String app, String stream, Object tracks, String callId);
-
-    /**
-     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 鍙槸鍦板潃鎷兼帴锛岃繑鍥炵殑ip浣跨敤杩滅▼璁块棶ip锛岄�傜敤涓巣lm涓巜vp鍦ㄤ竴鍙颁富鏈虹殑鎯呭喌
-     * @param app
-     * @param stream
-     * @return
-     */
-    StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks, String addr, String callId, boolean isPlay);
+    boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java
index f8486a8..79bdf78 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java
@@ -3,8 +3,8 @@
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;
 import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
 import com.github.pagehelper.PageInfo;
@@ -73,13 +73,13 @@
      * @param errorEvent 淇′护閿欒浜嬩欢
      * @param timeoutCallback 瓒呮椂浜嬩欢
      */
-    void broadcastInvite(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem,  ZlmHttpHookSubscribe.Event hookEvent,
+    void broadcastInvite(ParentPlatform platform, String channelId, MediaServer mediaServerItem, HookSubscribe.Event hookEvent,
                          SipSubscribe.Event errorEvent, InviteTimeOutCallback timeoutCallback) throws InvalidArgumentException, ParseException, SipException;
 
     /**
      * 璇煶鍠婅瘽鍥炲BYE
      */
-    void stopBroadcast(ParentPlatform platform, DeviceChannel channel, String stream,boolean sendBye, MediaServerItem mediaServerItem);
+    void stopBroadcast(ParentPlatform platform, DeviceChannel channel, String stream,boolean sendBye, MediaServer mediaServerItem);
 
     void addSimulatedSubscribeInfo(ParentPlatform parentPlatform);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
index bb2e2be..b3cab0e 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -7,8 +7,8 @@
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.bean.ErrorCallback;
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
@@ -26,20 +26,20 @@
  */
 public interface IPlayService {
 
-    void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channelId,
+    void play(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channelId,
               ErrorCallback<Object> callback);
-    SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback);
+    SSRCInfo play(MediaServer mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback);
 
-    StreamInfo onPublishHandlerForPlay(MediaServerItem mediaServerItem, HookParam hookParam, String deviceId, String channelId);
+    StreamInfo onPublishHandlerForPlay(MediaServer mediaServerItem, MediaInfo mediaInfo, String deviceId, String channelId);
 
-    MediaServerItem getNewMediaServerItem(Device device);
+    MediaServer getNewMediaServerItem(Device device);
 
     void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
-    void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
+    void playBack(MediaServer mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
     void zlmServerOffline(String mediaServerId);
 
     void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
-    void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId,  String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
+    void download(MediaServer mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
 
     StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
 
@@ -47,7 +47,7 @@
 
     AudioBroadcastResult audioBroadcast(Device device, String channelId, Boolean broadcastMode);
 
-    boolean audioBroadcastCmd(Device device, String channelId, MediaServerItem mediaServerItem, String app, String stream, int timeout, boolean isFromPlatform, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException;
+    boolean audioBroadcastCmd(Device device, String channelId, MediaServer mediaServerItem, String app, String stream, int timeout, boolean isFromPlatform, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException;
 
     boolean audioBroadcastInUse(Device device, String channelId);
 
@@ -59,10 +59,9 @@
 
     void startPushStream(SendRtpItem sendRtpItem, SIPResponse sipResponse, ParentPlatform platform, CallIdHeader callIdHeader);
 
-    void startSendRtpStreamHand(SendRtpItem sendRtpItem, Object correlationInfo,
-                                JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader);
+    void startSendRtpStreamFailHand(SendRtpItem sendRtpItem,ParentPlatform platform, CallIdHeader callIdHeader);
 
-    void talkCmd(Device device, String channelId, MediaServerItem mediaServerItem, String stream, AudioBroadcastEvent event);
+    void talkCmd(Device device, String channelId, MediaServer mediaServerItem, String stream, AudioBroadcastEvent event);
 
     void stopTalk(Device device, String channelId, Boolean streamIsReady);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java b/src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
index c4968a7..f3b5162 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
@@ -1,12 +1,14 @@
 package com.genersoft.iot.vmp.service;
 
-import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.common.GeneralCallback;
 import com.genersoft.iot.vmp.common.StreamInfo;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
 import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
+import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 import com.github.pagehelper.PageInfo;
+
+import java.util.Map;
 
 public interface IStreamProxyService {
 
@@ -18,17 +20,19 @@
 
     /**
      * 娣诲姞瑙嗛浠g悊鍒皕lm
+     *
      * @param param
      * @return
      */
-    JSONObject addStreamProxyToZlm(StreamProxyItem param);
+    WVPResult<String> addStreamProxyToZlm(StreamProxyItem param);
 
     /**
      * 浠巣lm绉婚櫎瑙嗛浠g悊
+     *
      * @param param
      * @return
      */
-    JSONObject removeStreamProxyFromZlm(StreamProxyItem param);
+    Boolean removeStreamProxyFromZlm(StreamProxyItem param);
 
     /**
      * 鍒嗛〉鏌ヨ
@@ -73,9 +77,10 @@
 
     /**
      * 鑾峰彇ffmpeg.cmd妯℃澘
+     *
      * @return
      */
-    JSONObject getFFmpegCMDs(MediaServerItem mediaServerItem);
+    Map<String, String> getFFmpegCMDs(MediaServer mediaServerItem);
 
     /**
      * 鏍规嵁app涓巗tream鑾峰彇streamProxy
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java b/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
index 10b1eff..1507331 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
@@ -1,9 +1,8 @@
 package com.genersoft.iot.vmp.service;
 
 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
+import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
 import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
 import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
 import com.github.pagehelper.PageInfo;
@@ -15,8 +14,6 @@
  * @author lin
  */
 public interface IStreamPushService {
-
-    List<StreamPushItem> handleJSON(String json, MediaServerItem mediaServerItem);
 
     /**
      * 灏嗗簲鐢ㄥ悕鍜屾祦ID鍔犲叆鍥芥爣鍏宠仈
diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java b/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java
index 771e4c8..c9a54bc 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java
@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.service.bean;
 
+import com.genersoft.iot.vmp.media.event.media.MediaRecordMp4Event;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
 
 /**
@@ -76,18 +77,18 @@
      */
     private long timeLen;
 
-    public static CloudRecordItem getInstance(OnRecordMp4HookParam param) {
+    public static CloudRecordItem getInstance(MediaRecordMp4Event param) {
         CloudRecordItem cloudRecordItem = new CloudRecordItem();
         cloudRecordItem.setApp(param.getApp());
         cloudRecordItem.setStream(param.getStream());
-        cloudRecordItem.setStartTime(param.getStart_time()*1000);
-        cloudRecordItem.setFileName(param.getFile_name());
-        cloudRecordItem.setFolder(param.getFolder());
-        cloudRecordItem.setFileSize(param.getFile_size());
-        cloudRecordItem.setFilePath(param.getFile_path());
-        cloudRecordItem.setMediaServerId(param.getMediaServerId());
-        cloudRecordItem.setTimeLen((long) param.getTime_len() * 1000);
-        cloudRecordItem.setEndTime((param.getStart_time() + (long)param.getTime_len()) * 1000);
+        cloudRecordItem.setStartTime(param.getRecordInfo().getStartTime()*1000);
+        cloudRecordItem.setFileName(param.getRecordInfo().getFileName());
+        cloudRecordItem.setFolder(param.getRecordInfo().getFolder());
+        cloudRecordItem.setFileSize(param.getRecordInfo().getFileSize());
+        cloudRecordItem.setFilePath(param.getRecordInfo().getFilePath());
+        cloudRecordItem.setMediaServerId(param.getMediaServer().getId());
+        cloudRecordItem.setTimeLen((long) param.getRecordInfo().getTimeLen() * 1000);
+        cloudRecordItem.setEndTime((param.getRecordInfo().getStartTime() + (long)param.getRecordInfo().getTimeLen()) * 1000);
         return cloudRecordItem;
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java b/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java
index 0a332ef..d7da931 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java
@@ -2,7 +2,7 @@
 
 import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 
 import java.util.EventObject;
 
@@ -15,7 +15,7 @@
 
     private String msg;
     private T data;
-    private MediaServerItem mediaServerItem;
+    private MediaServer mediaServerItem;
     private JSONObject response;
     private SipSubscribe.EventResult<EventObject> event;
 
@@ -35,11 +35,11 @@
         this.data = data;
     }
 
-    public MediaServerItem getMediaServerItem() {
+    public MediaServer getMediaServerItem() {
         return mediaServerItem;
     }
 
-    public void setMediaServerItem(MediaServerItem mediaServerItem) {
+    public void setMediaServerItem(MediaServer mediaServerItem) {
         this.mediaServerItem = mediaServerItem;
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/ResponseSendItemMsg.java b/src/main/java/com/genersoft/iot/vmp/service/bean/ResponseSendItemMsg.java
index 501621b..9d73384 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/bean/ResponseSendItemMsg.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/bean/ResponseSendItemMsg.java
@@ -1,7 +1,7 @@
 package com.genersoft.iot.vmp.service.bean;
 
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 
 /**
  * redis娑堟伅锛氫笅绾у洖澶嶆帹閫佷俊鎭�
@@ -11,7 +11,7 @@
 
     private SendRtpItem sendRtpItem;
 
-    private MediaServerItem mediaServerItem;
+    private MediaServer mediaServerItem;
 
     public SendRtpItem getSendRtpItem() {
         return sendRtpItem;
@@ -21,11 +21,11 @@
         this.sendRtpItem = sendRtpItem;
     }
 
-    public MediaServerItem getMediaServerItem() {
+    public MediaServer getMediaServerItem() {
         return mediaServerItem;
     }
 
-    public void setMediaServerItem(MediaServerItem mediaServerItem) {
+    public void setMediaServerItem(MediaServer mediaServerItem) {
         this.mediaServerItem = mediaServerItem;
     }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java
index a23252f..6ff0746 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java
@@ -5,12 +5,12 @@
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
+import com.genersoft.iot.vmp.media.event.media.MediaRecordMp4Event;
 import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
 import com.genersoft.iot.vmp.service.ICloudRecordService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
 import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -24,6 +24,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import java.time.*;
@@ -51,7 +53,7 @@
     private VideoStreamSessionManager streamSession;
 
     @Override
-    public PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) {
+    public PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServer> mediaServerItems) {
         // 寮�濮嬫椂闂村拰缁撴潫鏃堕棿鍦ㄦ暟鎹簱涓兘鏄互绉掍负鍗曚綅鐨�
         Long startTimeStamp = null;
         Long endTimeStamp = null;
@@ -76,7 +78,7 @@
     }
 
     @Override
-    public List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) {
+    public List<String> getDateList(String app, String stream, int year, int month, List<MediaServer> mediaServerItems) {
         LocalDate startDate = LocalDate.of(year, month, 1);
         LocalDate endDate;
         if (month == 12) {
@@ -99,19 +101,20 @@
         return new ArrayList<>(resultSet);
     }
 
-    @Override
-    public void addRecord(OnRecordMp4HookParam param) {
-        CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(param);
-        StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaRecordMp4Event event) {
+        CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(event);
+        StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(event.getApp(), event.getStream());
         if (streamAuthorityInfo != null) {
             cloudRecordItem.setCallId(streamAuthorityInfo.getCallId());
         }
-        logger.info("[娣诲姞褰曞儚璁板綍] {}/{} 鏂囦欢澶у皬锛歿}, 鏃堕暱锛� {}绉�", param.getApp(), param.getStream(), param.getFile_size(),param.getTime_len());
+        logger.info("[娣诲姞褰曞儚璁板綍] {}/{} 鍐呭锛歿}", event.getApp(), event.getStream(), event.getRecordInfo());
         cloudRecordServiceMapper.add(cloudRecordItem);
     }
 
     @Override
-    public String addTask(String app, String stream, MediaServerItem mediaServerItem, String startTime, String endTime,
+    public String addTask(String app, String stream, MediaServer mediaServerItem, String startTime, String endTime,
                           String callId, String remoteHost, boolean filterMediaServer) {
         // 鍙傛暟鏍¢獙
         assert app != null;
@@ -128,7 +131,7 @@
             endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
         }
 
-        List<MediaServerItem> mediaServers = new ArrayList<>();
+        List<MediaServer> mediaServers = new ArrayList<>();
         mediaServers.add(mediaServerItem);
         // 妫�绱㈢浉鍏崇殑褰曞儚鏂囦欢
         List<String> filePathList = cloudRecordServiceMapper.queryRecordFilePathList(app, stream, startTimeStamp,
@@ -146,7 +149,7 @@
     @Override
     public JSONArray queryTask(String app, String stream, String callId, String taskId, String mediaServerId,
                                Boolean isEnd, String scheme) {
-        MediaServerItem mediaServerItem = null;
+        MediaServer mediaServerItem = null;
         if (mediaServerId == null) {
             mediaServerItem = mediaServerService.getDefaultMediaServer();
         }else {
@@ -183,10 +186,10 @@
 
         }
 
-        List<MediaServerItem> mediaServerItems;
+        List<MediaServer> mediaServerItems;
         if (!ObjectUtils.isEmpty(mediaServerId)) {
             mediaServerItems = new ArrayList<>();
-            MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
+            MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId);
             if (mediaServerItem == null) {
                 throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒版祦濯掍綋: " + mediaServerId);
             }
@@ -229,7 +232,7 @@
             throw new ControllerException(ErrorCode.ERROR400.getCode(), "璧勬簮涓嶅瓨鍦�");
         }
         String filePath = recordItem.getFilePath();
-        MediaServerItem mediaServerItem = mediaServerService.getOne(recordItem.getMediaServerId());
+        MediaServer mediaServerItem = mediaServerService.getOne(recordItem.getMediaServerId());
         return CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath);
     }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
index 2c2674f..8fb772d 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -14,12 +14,11 @@
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler;
-import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.IDeviceChannelService;
 import com.genersoft.iot.vmp.service.IDeviceService;
 import com.genersoft.iot.vmp.service.IInviteStreamService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
 import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
@@ -54,6 +53,7 @@
 
     @Autowired
     private SIPCommander cmder;
+
     @Autowired
     private DynamicTask dynamicTask;
 
@@ -101,9 +101,6 @@
 
     @Autowired
     private AudioBroadcastManager audioBroadcastManager;
-
-    @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
 
     @Override
     public void online(Device device, SipTransactionInfo sipTransactionInfo) {
@@ -244,12 +241,8 @@
                 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(deviceId, audioBroadcastCatch.getChannelId(), null, null);
                 if (sendRtpItem != null) {
                     redisCatchStorage.deleteSendRTPServer(deviceId, sendRtpItem.getChannelId(), null, null);
-                    MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
-                    Map<String, Object> param = new HashMap<>();
-                    param.put("vhost", "__defaultVhost__");
-                    param.put("app", sendRtpItem.getApp());
-                    param.put("stream", sendRtpItem.getStream());
-                    zlmresTfulUtils.stopSendRtp(mediaInfo, param);
+                    MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+                    mediaServerService.stopSendRtp(mediaInfo, sendRtpItem.getApp(), sendRtpItem.getStream(), null);
                 }
 
                 audioBroadcastManager.del(deviceId, audioBroadcastCatch.getChannelId());
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
index 9dc86f8..6e00960 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
@@ -6,13 +6,18 @@
 import com.genersoft.iot.vmp.common.InviteSessionStatus;
 import com.genersoft.iot.vmp.common.InviteSessionType;
 import com.genersoft.iot.vmp.common.VideoManagerConstants;
+import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
+import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent;
 import com.genersoft.iot.vmp.service.IInviteStreamService;
 import com.genersoft.iot.vmp.service.bean.ErrorCallback;
+import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
@@ -31,6 +36,35 @@
     @Autowired
     private RedisTemplate<Object, Object> redisTemplate;
 
+    @Autowired
+    private IVideoManagerStorage storage;
+
+    /**
+     * 娴佸埌鏉ョ殑澶勭悊
+     */
+    @Async("taskExecutor")
+    @org.springframework.context.event.EventListener
+    public void onApplicationEvent(MediaArrivalEvent event) {
+//        if ("rtsp".equals(event.getSchema()) && "rtp".equals(event.getApp())) {
+//
+//        }
+    }
+
+    /**
+     * 娴佺寮�鐨勫鐞�
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaDepartureEvent event) {
+        if ("rtsp".equals(event.getSchema()) && "rtp".equals(event.getApp())) {
+            InviteInfo inviteInfo = getInviteInfoByStream(null, event.getStream());
+            if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) {
+                removeInviteInfo(inviteInfo);
+                storage.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
+            }
+        }
+    }
+
     @Override
     public void updateInviteInfo(InviteInfo inviteInfo) {
         if (inviteInfo == null || (inviteInfo.getDeviceId() == null || inviteInfo.getChannelId() == null)) {
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
deleted file mode 100755
index 190d665..0000000
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
+++ /dev/null
@@ -1,756 +0,0 @@
-package com.genersoft.iot.vmp.service.impl;
-
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONArray;
-import com.alibaba.fastjson2.JSONObject;
-import com.baomidou.dynamic.datasource.annotation.DS;
-import com.genersoft.iot.vmp.common.CommonCallback;
-import com.genersoft.iot.vmp.common.VideoManagerConstants;
-import com.genersoft.iot.vmp.conf.DynamicTask;
-import com.genersoft.iot.vmp.conf.SipConfig;
-import com.genersoft.iot.vmp.conf.UserSetting;
-import com.genersoft.iot.vmp.conf.exception.ControllerException;
-import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
-import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
-import com.genersoft.iot.vmp.media.zlm.*;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData;
-import com.genersoft.iot.vmp.service.IInviteStreamService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
-import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
-import com.genersoft.iot.vmp.service.bean.SSRCInfo;
-import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
-import com.genersoft.iot.vmp.storager.dao.MediaServerMapper;
-import com.genersoft.iot.vmp.utils.DateUtil;
-import com.genersoft.iot.vmp.utils.JsonUtil;
-import com.genersoft.iot.vmp.utils.redis.RedisUtil;
-import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
-import com.genersoft.iot.vmp.vmanager.bean.RecordFile;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.jdbc.datasource.DataSourceTransactionManager;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.TransactionDefinition;
-import org.springframework.transaction.TransactionStatus;
-import org.springframework.util.Assert;
-import org.springframework.util.ObjectUtils;
-
-import java.io.File;
-import java.time.LocalDateTime;
-import java.util.*;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-/**
- * 濯掍綋鏈嶅姟鍣ㄨ妭鐐圭鐞�
- */
-@Service
-@DS("master")
-public class MediaServerServiceImpl implements IMediaServerService {
-
-    private final static Logger logger = LoggerFactory.getLogger(MediaServerServiceImpl.class);
-
-    private final String zlmKeepaliveKeyPrefix = "zlm-keepalive_";
-
-    @Autowired
-    private SipConfig sipConfig;
-
-    @Autowired
-    private SSRCFactory ssrcFactory;
-
-    @Value("${server.ssl.enabled:false}")
-    private boolean sslEnabled;
-
-    @Value("${server.port}")
-    private Integer serverPort;
-
-    @Autowired
-    private UserSetting userSetting;
-
-    @Autowired
-    private SendRtpPortManager sendRtpPortManager;
-
-    @Autowired
-    private AssistRESTfulUtils assistRESTfulUtils;
-
-    @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
-
-    @Autowired
-    private MediaServerMapper mediaServerMapper;
-
-    @Autowired
-    private DataSourceTransactionManager dataSourceTransactionManager;
-
-    @Autowired
-    private TransactionDefinition transactionDefinition;
-
-
-    @Autowired
-    private ZLMServerFactory zlmServerFactory;
-
-    @Autowired
-    private EventPublisher publisher;
-
-    @Autowired
-    private DynamicTask dynamicTask;
-
-    @Autowired
-    private IRedisCatchStorage redisCatchStorage;
-
-    @Autowired
-    private IInviteStreamService inviteStreamService;
-
-    @Autowired
-    private RedisTemplate<Object, Object> redisTemplate;
-
-    @Qualifier("taskExecutor")
-    @Autowired
-    private ThreadPoolTaskExecutor taskExecutor;
-
-
-
-
-
-    /**
-     * 鍒濆鍖�
-     */
-    @Override
-    public void updateVmServer(List<MediaServerItem>  mediaServerItemList) {
-        logger.info("[zlm] 缂撳瓨鍒濆鍖� ");
-        for (MediaServerItem mediaServerItem : mediaServerItemList) {
-            if (ObjectUtils.isEmpty(mediaServerItem.getId())) {
-                continue;
-            }
-            // 鏇存柊
-            if (!ssrcFactory.hasMediaServerSSRC(mediaServerItem.getId())) {
-                ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null);
-            }
-            // 鏌ヨredis鏄惁瀛樺湪姝ediaServer
-            String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();
-            Boolean hasKey = redisTemplate.hasKey(key);
-            if (hasKey != null && ! hasKey) {
-                redisTemplate.opsForValue().set(key, mediaServerItem);
-            }
-        }
-    }
-
-
-    @Override
-    public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck,
-                                  boolean isPlayback, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode) {
-        if (mediaServerItem == null || mediaServerItem.getId() == null) {
-            logger.info("[openRTPServer] 澶辫触, mediaServerItem == null || mediaServerItem.getId() == null");
-            return null;
-        }
-        // 鑾峰彇mediaServer鍙敤鐨剆src
-        String ssrc;
-        if (presetSsrc != null) {
-            ssrc = presetSsrc;
-        }else {
-            if (isPlayback) {
-                ssrc = ssrcFactory.getPlayBackSsrc(mediaServerItem.getId());
-            }else {
-                ssrc = ssrcFactory.getPlaySsrc(mediaServerItem.getId());
-            }
-        }
-
-        if (streamId == null) {
-            streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase();
-        }
-        if (ssrcCheck && tcpMode > 0) {
-            // 鐩墠zlm涓嶆敮鎸� tcp妯″紡鏇存柊ssrc锛屾殏鏃跺叧闂璼src鏍¢獙
-            logger.warn("[openRTPServer] 骞冲彴瀵规帴鏃朵笅绾у彲鑳借嚜瀹氫箟ssrc锛屼絾鏄痶cp妯″紡zlm鏀舵祦鐩墠鏃犳硶鏇存柊ssrc锛屽彲鑳芥敹娴佽秴鏃讹紝姝ゆ椂璇蜂娇鐢╱dp鏀舵祦鎴栬�呭叧闂璼src鏍¢獙");
-        }
-        int rtpServerPort;
-        if (mediaServerItem.isRtpEnable()) {
-            rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck ? Long.parseLong(ssrc) : 0, port, onlyAuto, reUsePort, tcpMode);
-        } else {
-            rtpServerPort = mediaServerItem.getRtpProxyPort();
-        }
-        return new SSRCInfo(rtpServerPort, ssrc, streamId);
-    }
-
-    @Override
-    public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback, Integer port, Boolean onlyAuto) {
-        return openRTPServer(mediaServerItem, streamId, ssrc, ssrcCheck, isPlayback, port, onlyAuto, null, 0);
-    }
-
-
-    @Override
-    public void closeRTPServer(MediaServerItem mediaServerItem, String streamId) {
-        if (mediaServerItem == null) {
-            return;
-        }
-        zlmServerFactory.closeRtpServer(mediaServerItem, streamId);
-    }
-
-    @Override
-    public void closeRTPServer(MediaServerItem mediaServerItem, String streamId, CommonCallback<Boolean> callback) {
-        if (mediaServerItem == null) {
-            callback.run(false);
-            return;
-        }
-        zlmServerFactory.closeRtpServer(mediaServerItem, streamId, callback);
-    }
-
-    @Override
-    public void closeRTPServer(String mediaServerId, String streamId) {
-        MediaServerItem mediaServerItem = this.getOne(mediaServerId);
-        if (mediaServerItem != null && mediaServerItem.isRtpEnable()) {
-            closeRTPServer(mediaServerItem, streamId);
-        }
-        zlmresTfulUtils.closeStreams(mediaServerItem, "rtp", streamId);
-    }
-
-    @Override
-    public Boolean updateRtpServerSSRC(MediaServerItem mediaServerItem, String streamId, String ssrc) {
-        return zlmServerFactory.updateRtpServerSSRC(mediaServerItem, streamId, ssrc);
-    }
-
-    @Override
-    public void releaseSsrc(String mediaServerItemId, String ssrc) {
-        MediaServerItem mediaServerItem = getOne(mediaServerItemId);
-        if (mediaServerItem == null || ssrc == null) {
-            return;
-        }
-        ssrcFactory.releaseSsrc(mediaServerItemId, ssrc);
-    }
-
-    /**
-     * zlm 閲嶅惎鍚庨噸缃粬鐨勬帹娴佷俊鎭紝 TODO 缁欐鍦ㄤ娇鐢ㄧ殑璁惧鍙戦�佸仠姝㈠懡浠�
-     */
-    @Override
-    public void clearRTPServer(MediaServerItem mediaServerItem) {
-        ssrcFactory.reset(mediaServerItem.getId());
-
-    }
-
-
-    @Override
-    public void update(MediaServerItem mediaSerItem) {
-        mediaServerMapper.update(mediaSerItem);
-        MediaServerItem mediaServerItemInRedis = getOne(mediaSerItem.getId());
-        MediaServerItem mediaServerItemInDataBase = mediaServerMapper.queryOne(mediaSerItem.getId());
-        if (mediaServerItemInRedis == null || !ssrcFactory.hasMediaServerSSRC(mediaSerItem.getId())) {
-            ssrcFactory.initMediaServerSSRC(mediaServerItemInDataBase.getId(),null);
-        }
-        String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItemInDataBase.getId();
-        redisTemplate.opsForValue().set(key, mediaServerItemInDataBase);
-    }
-
-    @Override
-    public List<MediaServerItem> getAll() {
-        List<MediaServerItem> result = new ArrayList<>();
-        List<Object> mediaServerKeys = RedisUtil.scan(redisTemplate, String.format("%S*", VideoManagerConstants.MEDIA_SERVER_PREFIX+ userSetting.getServerId() + "_" ));
-        String onlineKey = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId();
-        for (Object mediaServerKey : mediaServerKeys) {
-            String key = (String) mediaServerKey;
-            MediaServerItem mediaServerItem = JsonUtil.redisJsonToObject(redisTemplate, key, MediaServerItem.class);
-            if (Objects.isNull(mediaServerItem)) {
-                continue;
-            }
-            // 妫�鏌ョ姸鎬�
-            Double aDouble = redisTemplate.opsForZSet().score(onlineKey, mediaServerItem.getId());
-            if (aDouble != null) {
-                mediaServerItem.setStatus(true);
-            }
-            result.add(mediaServerItem);
-        }
-        result.sort((serverItem1, serverItem2)->{
-            int sortResult = 0;
-            LocalDateTime localDateTime1 = LocalDateTime.parse(serverItem1.getCreateTime(), DateUtil.formatter);
-            LocalDateTime localDateTime2 = LocalDateTime.parse(serverItem2.getCreateTime(), DateUtil.formatter);
-
-            sortResult = localDateTime1.compareTo(localDateTime2);
-            return  sortResult;
-        });
-        return result;
-    }
-
-
-    @Override
-    public List<MediaServerItem> getAllFromDatabase() {
-        return mediaServerMapper.queryAll();
-    }
-
-    @Override
-    public List<MediaServerItem> getAllOnline() {
-        String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId();
-        Set<Object> mediaServerIdSet = redisTemplate.opsForZSet().reverseRange(key, 0, -1);
-
-        List<MediaServerItem> result = new ArrayList<>();
-        if (mediaServerIdSet != null && mediaServerIdSet.size() > 0) {
-            for (Object mediaServerId : mediaServerIdSet) {
-                String mediaServerIdStr = (String) mediaServerId;
-                String serverKey = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerIdStr;
-                result.add((MediaServerItem) redisTemplate.opsForValue().get(serverKey));
-            }
-        }
-        Collections.reverse(result);
-        return result;
-    }
-
-    /**
-     * 鑾峰彇鍗曚釜zlm鏈嶅姟鍣�
-     * @param mediaServerId 鏈嶅姟id
-     * @return MediaServerItem
-     */
-    @Override
-    public MediaServerItem getOne(String mediaServerId) {
-        if (mediaServerId == null) {
-            return null;
-        }
-        String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerId;
-        return JsonUtil.redisJsonToObject(redisTemplate, key, MediaServerItem.class);
-    }
-
-
-    @Override
-    public MediaServerItem getDefaultMediaServer() {
-        return mediaServerMapper.queryDefault();
-    }
-
-    @Override
-    public void clearMediaServerForOnline() {
-        String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId();
-        redisTemplate.delete(key);
-    }
-
-    @Override
-    public void add(MediaServerItem mediaServerItem) {
-        mediaServerItem.setCreateTime(DateUtil.getNow());
-        mediaServerItem.setUpdateTime(DateUtil.getNow());
-        mediaServerItem.setHookAliveInterval(30f);
-        JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
-        if (responseJSON != null) {
-            JSONArray data = responseJSON.getJSONArray("data");
-            if (data != null && data.size() > 0) {
-                ZLMServerConfig zlmServerConfig= JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
-                if (mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId()) != null) {
-                    throw new ControllerException(ErrorCode.ERROR100.getCode(),"淇濆瓨澶辫触锛屽獟浣撴湇鍔D [ " + zlmServerConfig.getGeneralMediaServerId() + " ] 宸插瓨鍦紝璇蜂慨鏀瑰獟浣撴湇鍔″櫒閰嶇疆");
-                }
-                mediaServerItem.setId(zlmServerConfig.getGeneralMediaServerId());
-                zlmServerConfig.setIp(mediaServerItem.getIp());
-                mediaServerMapper.add(mediaServerItem);
-                zlmServerOnline(zlmServerConfig);
-            }else {
-                throw new ControllerException(ErrorCode.ERROR100.getCode(),"杩炴帴澶辫触");
-            }
-
-        }else {
-            throw new ControllerException(ErrorCode.ERROR100.getCode(),"杩炴帴澶辫触");
-        }
-    }
-
-    @Override
-    public int addToDatabase(MediaServerItem mediaSerItem) {
-        return mediaServerMapper.add(mediaSerItem);
-    }
-
-    @Override
-    public int updateToDatabase(MediaServerItem mediaSerItem) {
-        int result = 0;
-        if (mediaSerItem.isDefaultServer()) {
-            TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
-            int delResult = mediaServerMapper.delDefault();
-            if (delResult == 0) {
-                logger.error("绉婚櫎鏁版嵁搴撻粯璁lm鑺傜偣澶辫触");
-                //浜嬪姟鍥炴粴
-                dataSourceTransactionManager.rollback(transactionStatus);
-                return 0;
-            }
-            result = mediaServerMapper.add(mediaSerItem);
-            dataSourceTransactionManager.commit(transactionStatus);     //鎵嬪姩鎻愪氦
-        }else {
-            result = mediaServerMapper.update(mediaSerItem);
-        }
-        return result;
-    }
-
-    /**
-     * 澶勭悊zlm涓婄嚎
-     * @param zlmServerConfig zlm涓婄嚎鎼哄甫鐨勫弬鏁�
-     */
-    @Override
-    public void zlmServerOnline(ZLMServerConfig zlmServerConfig) {
-
-        MediaServerItem serverItem = mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId());
-        if (serverItem == null) {
-            logger.warn("[鏈敞鍐岀殑zlm] 鎷掓帴鎺ュ叆锛歿}鏉ヨ嚜{}锛歿}", zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(),zlmServerConfig.getHttpPort() );
-            logger.warn("璇锋鏌LM鐨�<general.mediaServerId>閰嶇疆鏄惁涓嶹VP鐨�<media.id>涓�鑷�");
-            return;
-        }else {
-            logger.info("[ZLM] 姝e湪杩炴帴 : {} -> {}:{}",
-                    zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
-        }
-        serverItem.setHookAliveInterval(zlmServerConfig.getHookAliveInterval());
-        if (serverItem.getHttpPort() == 0) {
-            serverItem.setHttpPort(zlmServerConfig.getHttpPort());
-        }
-        if (serverItem.getHttpSSlPort() == 0) {
-            serverItem.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
-        }
-        if (serverItem.getRtmpPort() == 0) {
-            serverItem.setRtmpPort(zlmServerConfig.getRtmpPort());
-        }
-        if (serverItem.getRtmpSSlPort() == 0) {
-            serverItem.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
-        }
-        if (serverItem.getRtspPort() == 0) {
-            serverItem.setRtspPort(zlmServerConfig.getRtspPort());
-        }
-        if (serverItem.getRtspSSLPort() == 0) {
-            serverItem.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
-        }
-        if (serverItem.getRtpProxyPort() == 0) {
-            serverItem.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
-        }
-        serverItem.setStatus(true);
-
-        if (ObjectUtils.isEmpty(serverItem.getId())) {
-            logger.warn("[鏈敞鍐岀殑zlm] serverItem缂哄皯ID锛� 鏃犳硶鎺ュ叆锛歿}锛歿}", zlmServerConfig.getIp(),zlmServerConfig.getHttpPort() );
-            return;
-        }
-        mediaServerMapper.update(serverItem);
-        String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + zlmServerConfig.getGeneralMediaServerId();
-        if (!ssrcFactory.hasMediaServerSSRC(serverItem.getId())) {
-            ssrcFactory.initMediaServerSSRC(zlmServerConfig.getGeneralMediaServerId(), null);
-        }
-        redisTemplate.opsForValue().set(key, serverItem);
-        resetOnlineServerItem(serverItem);
-
-
-        if (serverItem.isAutoConfig()) {
-            setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable()));
-        }
-        final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId();
-        dynamicTask.stop(zlmKeepaliveKey);
-        dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(serverItem), (serverItem.getHookAliveInterval().intValue() + 5) * 1000);
-        publisher.zlmOnlineEventPublish(serverItem.getId());
-
-        logger.info("[ZLM] 杩炴帴鎴愬姛 {} - {}:{} ",
-                zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
-    }
-
-    class KeepAliveTimeoutRunnable implements Runnable{
-
-        private MediaServerItem serverItem;
-
-        public KeepAliveTimeoutRunnable(MediaServerItem serverItem) {
-            this.serverItem = serverItem;
-        }
-
-        @Override
-        public void run() {
-            logger.info("[zlm蹇冭烦鍒版湡]锛�" + serverItem.getId());
-            // 鍙戣捣http璇锋眰楠岃瘉zlm鏄惁纭疄鏃犳硶杩炴帴锛屽鏋滅‘瀹炴棤娉曡繛鎺ュ垯鍙戦�佺绾夸簨浠讹紝鍚﹀垯涓嶄綔澶勭悊
-            JSONObject mediaServerConfig = zlmresTfulUtils.getMediaServerConfig(serverItem);
-            if (mediaServerConfig != null && mediaServerConfig.getInteger("code") == 0) {
-                logger.info("[zlm蹇冭烦鍒版湡]锛歿}楠岃瘉鍚巣lm浠嶅湪绾匡紝鎭㈠蹇冭烦淇℃伅,璇锋鏌lm鏄惁鍙互姝e父鍚憌vp鍙戦�佸績璺�", serverItem.getId());
-                // 娣诲姞zlm淇℃伅
-                updateMediaServerKeepalive(serverItem.getId(), null);
-            }else {
-                publisher.zlmOfflineEventPublish(serverItem.getId());
-            }
-        }
-    }
-
-
-    @Override
-    public void zlmServerOffline(String mediaServerId) {
-        delete(mediaServerId);
-        final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + mediaServerId;
-        dynamicTask.stop(zlmKeepaliveKey);
-    }
-
-    @Override
-    public void resetOnlineServerItem(MediaServerItem serverItem) {
-        // 鏇存柊缂撳瓨
-        String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId();
-        // 浣跨敤zset鐨勫垎鏁颁綔涓哄綋鍓嶅苟鍙戦噺锛� 榛樿鍊艰缃负0
-        if (redisTemplate.opsForZSet().score(key, serverItem.getId()) == null) {  // 涓嶅瓨鍦ㄥ垯璁剧疆榛樿鍊� 宸插瓨鍦ㄥ垯閲嶇疆
-            redisTemplate.opsForZSet().add(key, serverItem.getId(), 0L);
-            // 鏌ヨ鏈嶅姟娴佹暟閲�
-            zlmresTfulUtils.getMediaList(serverItem, null, null, "rtsp",(mediaList ->{
-                Integer code = mediaList.getInteger("code");
-                if (code == 0) {
-                    JSONArray data = mediaList.getJSONArray("data");
-                    if (data != null) {
-                        redisTemplate.opsForZSet().add(key, serverItem.getId(), data.size());
-                    }
-                }
-            }));
-        }else {
-            clearRTPServer(serverItem);
-        }
-    }
-
-
-    @Override
-    public void addCount(String mediaServerId) {
-        if (mediaServerId == null) {
-            return;
-        }
-        String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId();
-        redisTemplate.opsForZSet().incrementScore(key, mediaServerId, 1);
-
-    }
-
-    @Override
-    public void removeCount(String mediaServerId) {
-        String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId();
-        redisTemplate.opsForZSet().incrementScore(key, mediaServerId, - 1);
-    }
-
-    /**
-     * 鑾峰彇璐熻浇鏈�浣庣殑鑺傜偣
-     * @return MediaServerItem
-     */
-    @Override
-    public MediaServerItem getMediaServerForMinimumLoad(Boolean hasAssist) {
-        String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId();
-        Long size = redisTemplate.opsForZSet().zCard(key);
-        if (size  == null || size == 0) {
-            logger.info("鑾峰彇璐熻浇鏈�浣庣殑鑺傜偣鏃舵棤鍦ㄧ嚎鑺傜偣");
-            return null;
-        }
-
-        // 鑾峰彇鍒嗘暟鏈�浣庣殑锛屽強骞跺彂鏈�浣庣殑
-        Set<Object> objects = redisTemplate.opsForZSet().range(key, 0, -1);
-        ArrayList<Object> mediaServerObjectS = new ArrayList<>(objects);
-        MediaServerItem mediaServerItem = null;
-        if (hasAssist == null) {
-            String mediaServerId = (String)mediaServerObjectS.get(0);
-            mediaServerItem = getOne(mediaServerId);
-        }else if (hasAssist) {
-            for (Object mediaServerObject : mediaServerObjectS) {
-                String mediaServerId = (String)mediaServerObject;
-                MediaServerItem serverItem = getOne(mediaServerId);
-                if (serverItem.getRecordAssistPort() > 0) {
-                    mediaServerItem = serverItem;
-                    break;
-                }
-            }
-        }else if (!hasAssist) {
-            for (Object mediaServerObject : mediaServerObjectS) {
-                String mediaServerId = (String)mediaServerObject;
-                MediaServerItem serverItem = getOne(mediaServerId);
-                if (serverItem.getRecordAssistPort() == 0) {
-                    mediaServerItem = serverItem;
-                    break;
-                }
-            }
-        }
-
-        return mediaServerItem;
-    }
-
-    /**
-     * 瀵箊lm鏈嶅姟鍣ㄨ繘琛屽熀纭�閰嶇疆
-     * @param mediaServerItem 鏈嶅姟ID
-     * @param restart 鏄惁閲嶅惎zlm
-     */
-    @Override
-    public void setZLMConfig(MediaServerItem mediaServerItem, boolean restart) {
-        logger.info("[ZLM] 姝e湪璁剧疆 锛歿} -> {}:{}",
-                mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
-        String protocol = sslEnabled ? "https" : "http";
-        String hookPrefix = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort);
-
-        Map<String, Object> param = new HashMap<>();
-        param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline
-        if (mediaServerItem.getRtspPort() != 0) {
-            param.put("ffmpeg.snap", "%s -rtsp_transport tcp -i %s -y -f mjpeg -frames:v 1 %s");
-        }
-        param.put("hook.enable","1");
-        param.put("hook.on_flow_report","");
-        param.put("hook.on_play",String.format("%s/on_play", hookPrefix));
-        param.put("hook.on_http_access","");
-        param.put("hook.on_publish", String.format("%s/on_publish", hookPrefix));
-        param.put("hook.on_record_ts","");
-        param.put("hook.on_rtsp_auth","");
-        param.put("hook.on_rtsp_realm","");
-        param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrefix));
-        param.put("hook.on_shell_login","");
-        param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrefix));
-        param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrefix));
-        param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrefix));
-        param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrefix));
-        param.put("hook.on_send_rtp_stopped",String.format("%s/on_send_rtp_stopped", hookPrefix));
-        param.put("hook.on_rtp_server_timeout",String.format("%s/on_rtp_server_timeout", hookPrefix));
-        param.put("hook.on_record_mp4",String.format("%s/on_record_mp4", hookPrefix));
-        param.put("hook.timeoutSec","20");
-        // 鎺ㄦ祦鏂紑鍚庡彲浠ュ湪瓒呮椂鏃堕棿鍐呴噸鏂拌繛鎺ヤ笂缁х画鎺ㄦ祦锛岃繖鏍锋挱鏀惧櫒浼氭帴鐫�鎾斁銆�
-        // 缃�0鍏抽棴姝ょ壒鎬�(鎺ㄦ祦鏂紑浼氬鑷寸珛鍗虫柇寮�鎾斁鍣�)
-        // 姝ゅ弬鏁颁笉搴斿ぇ浜庢挱鏀惧櫒瓒呮椂鏃堕棿
-        // 浼樺寲姝ゆ秷鎭互鏇村揩鐨勬敹鍒版祦娉ㄩ攢浜嬩欢
-        param.put("protocol.continue_push_ms", "3000" );
-        // 鏈�澶氱瓑寰呮湭鍒濆鍖栫殑Track鏃堕棿锛屽崟浣嶆绉掞紝瓒呮椂涔嬪悗浼氬拷鐣ユ湭鍒濆鍖栫殑Track, 璁剧疆姝ら�夐」浼樺寲閭d簺闊抽閿欒鐨勪笉瑙勮寖娴侊紝
-        // 绛墇lm鏀寔缁欐瘡涓猺tpServer璁剧疆鍏抽棴闊抽鐨勬椂鍊欏彲浠ヤ笉璁剧疆姝ら�夐」
-        if (mediaServerItem.isRtpEnable() && !ObjectUtils.isEmpty(mediaServerItem.getRtpPortRange())) {
-            param.put("rtp_proxy.port_range", mediaServerItem.getRtpPortRange().replace(",", "-"));
-        }
-
-        if (!ObjectUtils.isEmpty(mediaServerItem.getRecordPath())) {
-            File recordPathFile = new File(mediaServerItem.getRecordPath());
-            param.put("protocol.mp4_save_path", recordPathFile.getParentFile().getPath());
-            param.put("protocol.downloadRoot", recordPathFile.getParentFile().getPath());
-            param.put("record.appName", recordPathFile.getName());
-        }
-
-        JSONObject responseJSON = zlmresTfulUtils.setServerConfig(mediaServerItem, param);
-
-        if (responseJSON != null && responseJSON.getInteger("code") == 0) {
-            if (restart) {
-                logger.info("[ZLM] 璁剧疆鎴愬姛,寮�濮嬮噸鍚互淇濊瘉閰嶇疆鐢熸晥 {} -> {}:{}",
-                        mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
-                zlmresTfulUtils.restartServer(mediaServerItem);
-            }else {
-                logger.info("[ZLM] 璁剧疆鎴愬姛 {} -> {}:{}",
-                        mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
-            }
-
-
-        }else {
-            logger.info("[ZLM] 璁剧疆zlm澶辫触 {} -> {}:{}",
-                    mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
-        }
-
-
-    }
-
-
-    @Override
-    public MediaServerItem checkMediaServer(String ip, int port, String secret) {
-        if (mediaServerMapper.queryOneByHostAndPort(ip, port) != null) {
-            throw new ControllerException(ErrorCode.ERROR100.getCode(), "姝よ繛鎺ュ凡瀛樺湪");
-        }
-        MediaServerItem mediaServerItem = new MediaServerItem();
-        mediaServerItem.setIp(ip);
-        mediaServerItem.setHttpPort(port);
-        mediaServerItem.setSecret(secret);
-        JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
-        if (responseJSON == null) {
-            throw new ControllerException(ErrorCode.ERROR100.getCode(), "杩炴帴澶辫触");
-        }
-        JSONArray data = responseJSON.getJSONArray("data");
-        ZLMServerConfig zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
-        if (zlmServerConfig == null) {
-            throw new ControllerException(ErrorCode.ERROR100.getCode(), "璇诲彇閰嶇疆澶辫触");
-        }
-        if (mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId()) != null) {
-            throw new ControllerException(ErrorCode.ERROR100.getCode(), "濯掍綋鏈嶅姟ID [" + zlmServerConfig.getGeneralMediaServerId() + " ] 宸插瓨鍦紝璇蜂慨鏀瑰獟浣撴湇鍔″櫒閰嶇疆");
-        }
-        mediaServerItem.setHttpSSlPort(zlmServerConfig.getHttpPort());
-        mediaServerItem.setRtmpPort(zlmServerConfig.getRtmpPort());
-        mediaServerItem.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
-        mediaServerItem.setRtspPort(zlmServerConfig.getRtspPort());
-        mediaServerItem.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
-        mediaServerItem.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
-        mediaServerItem.setStreamIp(ip);
-        mediaServerItem.setHookIp(sipConfig.getIp().split(",")[0]);
-        mediaServerItem.setSdpIp(ip);
-        return mediaServerItem;
-    }
-
-    @Override
-    public boolean checkMediaRecordServer(String ip, int port) {
-        boolean result = false;
-        OkHttpClient client = new OkHttpClient();
-        String url = String.format("http://%s:%s/index/api/record",  ip, port);
-        Request request = new Request.Builder()
-                .get()
-                .url(url)
-                .build();
-        try {
-            Response response = client.newCall(request).execute();
-            if (response != null) {
-                result = true;
-            }
-        } catch (Exception e) {}
-
-        return result;
-    }
-
-    @Override
-    public void delete(String id) {
-        redisTemplate.opsForZSet().remove(VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId(), id);
-        String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + id;
-        redisTemplate.delete(key);
-    }
-    @Override
-    public void deleteDb(String id){
-        //鍚屾鍒犻櫎鏁版嵁搴撲腑鐨勬暟鎹�
-        mediaServerMapper.delOne(id);
-    }
-
-    @Override
-    public void updateMediaServerKeepalive(String mediaServerId, ServerKeepaliveData data) {
-        MediaServerItem mediaServerItem = getOne(mediaServerId);
-        if (mediaServerItem == null) {
-            // 缂撳瓨涓嶅瓨鍦紝浠庢暟鎹簱鏌ヨ锛屽鏋滄暟鎹簱涓嶅瓨鍦ㄥ垯鏄敊璇殑
-            mediaServerItem = getOneFromDatabase(mediaServerId);
-            if (mediaServerItem == null) {
-                logger.warn("[鏇存柊ZLM 淇濇椿淇℃伅] 娴佸獟浣搟}灏氭湭鍔犲叆浣跨敤,璇锋鏌ヨ妭鐐逛腑鏄惁鍚湁姝ゆ祦濯掍綋 ", mediaServerId);
-                return;
-            }
-            // zlm杩炴帴閲嶈瘯
-            logger.warn("[鏇存柊ZLM 淇濇椿淇℃伅]灏濊瘯閾炬帴zml id {}", mediaServerId);
-            ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null);
-            String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();
-            redisTemplate.opsForValue().set(key, mediaServerItem);
-            resetOnlineServerItem(mediaServerItem);
-            clearRTPServer(mediaServerItem);
-        }
-        final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + mediaServerItem.getId();
-        dynamicTask.stop(zlmKeepaliveKey);
-        dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(mediaServerItem), (mediaServerItem.getHookAliveInterval().intValue() + 5) * 1000);
-    }
-
-    private MediaServerItem getOneFromDatabase(String mediaServerId) {
-        return mediaServerMapper.queryOne(mediaServerId);
-    }
-
-    @Override
-    public void syncCatchFromDatabase() {
-        List<MediaServerItem> allInCatch = getAll();
-        List<MediaServerItem> allInDatabase = mediaServerMapper.queryAll();
-        Map<String, MediaServerItem> mediaServerItemMap = new HashMap<>();
-
-        for (MediaServerItem mediaServerItem : allInDatabase) {
-            mediaServerItemMap.put(mediaServerItem.getId(), mediaServerItem);
-        }
-        for (MediaServerItem mediaServerItem : allInCatch) {
-            if (!mediaServerItemMap.containsKey(mediaServerItem.getId())) {
-                delete(mediaServerItem.getId());
-            }
-        }
-    }
-
-    @Override
-    public MediaServerLoad getLoad(MediaServerItem mediaServerItem) {
-        MediaServerLoad result = new MediaServerLoad();
-        result.setId(mediaServerItem.getId());
-        result.setPush(redisCatchStorage.getPushStreamCount(mediaServerItem.getId()));
-        result.setProxy(redisCatchStorage.getProxyStreamCount(mediaServerItem.getId()));
-
-        result.setGbReceive(inviteStreamService.getStreamInfoCount(mediaServerItem.getId()));
-        result.setGbSend(redisCatchStorage.getGbSendCount(mediaServerItem.getId()));
-        return result;
-    }
-
-    @Override
-    public List<MediaServerItem> getAllWithAssistPort() {
-        return mediaServerMapper.queryAllWithAssistPort();
-    }
-}
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 784f43f..5c819e5 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -1,109 +1,331 @@
 package com.genersoft.iot.vmp.service.impl;
 
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONArray;
-import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.common.StreamInfo;
-import com.genersoft.iot.vmp.conf.MediaConfig;
-import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.common.InviteInfo;
+import com.genersoft.iot.vmp.common.InviteSessionType;
+import com.genersoft.iot.vmp.common.VideoManagerConstants;
+import com.genersoft.iot.vmp.conf.UserSetting;
+import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
+import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
+import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
+import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
-import com.genersoft.iot.vmp.service.IMediaServerService;
-import com.genersoft.iot.vmp.service.IMediaService;
+import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
+import com.genersoft.iot.vmp.service.*;
+import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
+import com.genersoft.iot.vmp.utils.DateUtil;
+import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
+import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
+import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.util.ObjectUtils;
 
+import javax.sip.InvalidArgumentException;
+import javax.sip.SipException;
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 @Service
 public class MediaServiceImpl implements IMediaService {
+
+    private final static Logger logger = LoggerFactory.getLogger(MediaServiceImpl.class);
 
     @Autowired
     private IRedisCatchStorage redisCatchStorage;
 
     @Autowired
+    private IStreamProxyService streamProxyService;
+
+    @Autowired
+    private UserSetting userSetting;
+
+    @Autowired
+    private RedisTemplate<Object, Object> redisTemplate;
+
+    @Autowired
+    private IUserService userService;
+
+    @Autowired
+    private IInviteStreamService inviteStreamService;
+
+    @Autowired
+    private VideoStreamSessionManager sessionManager;
+
+    @Autowired
     private IVideoManagerStorage storager;
 
     @Autowired
-    private IMediaServerService mediaServerService;
-
+    private ZLMMediaListManager zlmMediaListManager;
 
     @Autowired
-    private MediaConfig mediaConfig;
+    private IDeviceService deviceService;
 
     @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
+    private ISIPCommanderForPlatform commanderForPlatform;
 
-
+    @Autowired
+    private ISIPCommander commander;
 
     @Override
-    public StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks, String callId) {
-        return getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, null, callId, true);
+    public boolean authenticatePlay(String app, String stream, String callId) {
+        if (app == null || stream == null) {
+            return false;
+        }
+        if ("rtp".equals(app)) {
+            return true;
+        }
+        StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
+        if (streamAuthorityInfo == null || streamAuthorityInfo.getCallId() == null) {
+            return true;
+        }
+        return streamAuthorityInfo.getCallId().equals(callId);
     }
 
     @Override
-    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, String addr, boolean authority) {
-        StreamInfo streamInfo = null;
-        if (mediaServerId == null) {
-            mediaServerId = mediaConfig.getId();
-        }
-        MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
-        if (mediaInfo == null) {
-            return null;
-        }
-        String calld = null;
-        StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
-        if (streamAuthorityInfo != null) {
-            calld = streamAuthorityInfo.getCallId();
-        }
-        JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, app, stream);
-        if (mediaList != null) {
-            if (mediaList.getInteger("code") == 0) {
-                JSONArray data = mediaList.getJSONArray("data");
-                if (data == null) {
-                    return null;
+    public ResultForOnPublish authenticatePublish(MediaServer mediaServer, String app, String stream, String params) {
+        // 鎺ㄦ祦閴存潈鐨勫鐞�
+        if (!"rtp".equals(app)) {
+            StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, stream);
+            if (streamProxyItem != null) {
+                ResultForOnPublish result = new ResultForOnPublish();
+                result.setEnable_audio(streamProxyItem.isEnableAudio());
+                result.setEnable_mp4(streamProxyItem.isEnableMp4());
+                return result;
+            }
+            if (userSetting.getPushAuthority()) {
+                // 瀵逛簬鎺ㄦ祦杩涜閴存潈
+                Map<String, String> paramMap = urlParamToMap(params);
+                // 鎺ㄦ祦閴存潈
+                if (params == null) {
+                    logger.info("鎺ㄦ祦閴存潈澶辫触锛� 缂哄皯蹇呰鍙傛暟锛歴ign=md5(user琛ㄧ殑pushKey)");
+                    throw new ControllerException(ErrorCode.ERROR401.getCode(), "Unauthorized");
                 }
-                JSONObject mediaJSON = data.getJSONObject(0);
-                JSONArray tracks = mediaJSON.getJSONArray("tracks");
-                if (authority) {
-                    streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr, calld, true);
-                }else {
-                    streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr,null, true);
+
+                String sign = paramMap.get("sign");
+                if (sign == null) {
+                    logger.info("鎺ㄦ祦閴存潈澶辫触锛� 缂哄皯蹇呰鍙傛暟锛歴ign=md5(user琛ㄧ殑pushKey)");
+                    throw new ControllerException(ErrorCode.ERROR401.getCode(), "Unauthorized");
+                }
+                // 鎺ㄦ祦鑷畾涔夋挱鏀鹃壌鏉冪爜
+                String callId = paramMap.get("callId");
+                // 閴存潈閰嶇疆
+                boolean hasAuthority = userService.checkPushAuthority(callId, sign);
+                if (!hasAuthority) {
+                    logger.info("鎺ㄦ祦閴存潈澶辫触锛� sign 鏃犳潈闄�: callId={}. sign={}", callId, sign);
+                    throw new ControllerException(ErrorCode.ERROR401.getCode(), "Unauthorized");
+                }
+                StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(app, stream, mediaServer.getId());
+                streamAuthorityInfo.setCallId(callId);
+                streamAuthorityInfo.setSign(sign);
+                // 閴存潈閫氳繃
+                redisCatchStorage.updateStreamAuthorityInfo(app, stream, streamAuthorityInfo);
+            }
+        } else {
+            zlmMediaListManager.sendStreamEvent(app, stream, mediaServer.getId());
+        }
+
+
+        ResultForOnPublish result = new ResultForOnPublish();
+        result.setEnable_audio(true);
+
+        // 鏄惁褰曞儚
+        if ("rtp".equals(app)) {
+            result.setEnable_mp4(userSetting.getRecordSip());
+        } else {
+            result.setEnable_mp4(userSetting.isRecordPushLive());
+        }
+        // 鍥芥爣娴�
+        if ("rtp".equals(app)) {
+
+            InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, stream);
+
+            // 鍗曠鍙fā寮忎笅淇敼娴� ID
+            if (!mediaServer.isRtpEnable() && inviteInfo == null) {
+                String ssrc = String.format("%010d", Long.parseLong(stream, 16));
+                inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc);
+                if (inviteInfo != null) {
+                    result.setStream_replace(inviteInfo.getStream());
+                    logger.info("[ZLM HOOK]鎺ㄦ祦閴存潈 stream: {} 鏇挎崲涓� {}", stream, inviteInfo.getStream());
+                    stream = inviteInfo.getStream();
+                }
+            }
+
+            // 璁剧疆闊抽淇℃伅鍙婂綍鍒朵俊鎭�
+            List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, stream);
+            if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) {
+
+                // 涓哄綍鍒跺浗鏍囨ā鎷熶竴涓壌鏉冧俊鎭�, 鏂逛究鍚庣画鍐欏叆褰曞儚鏂囦欢鏃朵娇鐢�
+                StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(app, stream, mediaServer.getId());
+                streamAuthorityInfo.setApp(app);
+                streamAuthorityInfo.setStream(ssrcTransactionForAll.get(0).getStream());
+                streamAuthorityInfo.setCallId(ssrcTransactionForAll.get(0).getSipTransactionInfo().getCallId());
+
+                redisCatchStorage.updateStreamAuthorityInfo(app, ssrcTransactionForAll.get(0).getStream(), streamAuthorityInfo);
+
+                String deviceId = ssrcTransactionForAll.get(0).getDeviceId();
+                String channelId = ssrcTransactionForAll.get(0).getChannelId();
+                DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
+                if (deviceChannel != null) {
+                    result.setEnable_audio(deviceChannel.isHasAudio());
+                }
+                // 濡傛灉鏄綍鍍忎笅杞藉氨璁剧疆瑙嗛闂撮殧鍗佺
+                if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) {
+                    // 鑾峰彇褰曞儚鐨勬�绘椂闀匡紝鐒跺悗璁剧疆涓鸿繖涓棰戠殑鏃堕暱
+                    InviteInfo inviteInfoForDownload = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, stream);
+                    if (inviteInfoForDownload != null && inviteInfoForDownload.getStreamInfo() != null) {
+                        String startTime = inviteInfoForDownload.getStreamInfo().getStartTime();
+                        String endTime = inviteInfoForDownload.getStreamInfo().getEndTime();
+                        long difference = DateUtil.getDifference(startTime, endTime) / 1000;
+                        result.setMp4_max_second((int) difference);
+                        result.setEnable_mp4(true);
+                        // 璁剧疆涓�2淇濊瘉寰楀埌鐨刴p4鐨勬椂闀挎槸姝e父鐨�
+                        result.setModify_stamp(2);
+                    }
+                }
+                // 濡傛灉鏄痶alk瀵硅锛屽垯榛樿鑾峰彇澹伴煶
+                if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.TALK) {
+                    result.setEnable_audio(true);
+                }
+            }
+        } else if (app.equals("broadcast")) {
+            result.setEnable_audio(true);
+        } else if (app.equals("talk")) {
+            result.setEnable_audio(true);
+        }
+        if (app.equalsIgnoreCase("rtp")) {
+            String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + stream;
+            OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo) redisTemplate.opsForValue().get(receiveKey);
+
+            String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + stream;
+            OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo) redisTemplate.opsForValue().get(receiveKeyForPS);
+            if (otherRtpSendInfo != null || otherPsSendInfo != null) {
+                result.setEnable_mp4(true);
+            }
+        }
+        return result;
+    }
+
+    private Map<String, String> urlParamToMap(String params) {
+        HashMap<String, String> map = new HashMap<>();
+        if (ObjectUtils.isEmpty(params)) {
+            return map;
+        }
+        String[] paramsArray = params.split("&");
+        if (paramsArray.length == 0) {
+            return map;
+        }
+        for (String param : paramsArray) {
+            String[] paramArray = param.split("=");
+            if (paramArray.length == 2) {
+                map.put(paramArray[0], paramArray[1]);
+            }
+        }
+        return map;
+    }
+
+    @Override
+    public boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema) {
+        boolean result = false;
+        // 鍥芥爣绫诲瀷鐨勬祦
+        if ("rtp".equals(app)) {
+            result = userSetting.getStreamOnDemand();
+            // 鍥芥爣娴侊紝 鐐规挱/褰曞儚鍥炴斁/褰曞儚涓嬭浇
+            InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, stream);
+            // 鐐规挱
+            if (inviteInfo != null) {
+                // 褰曞儚涓嬭浇
+                if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) {
+                    return false;
+                }
+                // 鏀跺埌鏃犱汉瑙傜湅璇存槑娴佷篃娌℃湁鍦ㄥ線涓婄骇鎺ㄩ��
+                if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) {
+                    List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChannelId(
+                            inviteInfo.getChannelId());
+                    if (!sendRtpItems.isEmpty()) {
+                        for (SendRtpItem sendRtpItem : sendRtpItems) {
+                            ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
+                            try {
+                                commanderForPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
+                            } catch (SipException | InvalidArgumentException | ParseException e) {
+                                logger.error("[鍛戒护鍙戦�佸け璐 鍥芥爣绾ц仈 鍙戦�丅YE: {}", e.getMessage());
+                            }
+                            redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
+                                    sendRtpItem.getCallId(), sendRtpItem.getStream());
+                            if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) {
+                                MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
+                                        sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(),
+                                        sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId());
+                                messageForPushChannel.setPlatFormIndex(parentPlatform.getId());
+                                redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel);
+                            }
+                        }
+                    }
+                }
+                Device device = deviceService.getDevice(inviteInfo.getDeviceId());
+                if (device != null) {
+                    try {
+                        // 澶氭煡璇竴娆¢槻姝㈠凡缁忚澶勭悊浜�
+                        InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(),
+                                inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
+                        if (info != null) {
+                            commander.streamByeCmd(device, inviteInfo.getChannelId(),
+                                    inviteInfo.getStream(), null);
+                        } else {
+                            logger.info("[鏃犱汉瑙傜湅] 鏈壘鍒拌澶囩殑鐐规挱淇℃伅锛� {}锛� 娴侊細{}", inviteInfo.getDeviceId(), stream);
+                        }
+                    } catch (InvalidArgumentException | ParseException | SipException |
+                             SsrcTransactionNotFoundException e) {
+                        logger.error("[鏃犱汉瑙傜湅]鐐规挱锛� 鍙戦�丅YE澶辫触 {}", e.getMessage());
+                    }
+                } else {
+                    logger.info("[鏃犱汉瑙傜湅] 鏈壘鍒拌澶囷細 {}锛屾祦锛歿}", inviteInfo.getDeviceId(), stream);
+                }
+
+                inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(),
+                        inviteInfo.getChannelId(), inviteInfo.getStream());
+                storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
+                return result;
+            }
+            SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, stream, null);
+            if (sendRtpItem != null && "talk".equals(sendRtpItem.getApp())) {
+                return false;
+            }
+        } else if ("talk".equals(app) || "broadcast".equals(app)) {
+            return false;
+        } else {
+            // 闈炲浗鏍囨祦 鎺ㄦ祦/鎷夋祦浠g悊
+            // 鎷夋祦浠g悊
+            StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, stream);
+            if (streamProxyItem != null) {
+                if (streamProxyItem.isEnableRemoveNoneReader()) {
+                    // 鏃犱汉瑙傜湅鑷姩绉婚櫎
+                    result = true;
+                    streamProxyService.del(app, stream);
+                    String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl();
+                    logger.info("[{}/{}]<-[{}] 鎷夋祦浠g悊鏃犱汉瑙傜湅宸茬粡绉婚櫎", app, stream, url);
+                } else if (streamProxyItem.isEnableDisableNoneReader()) {
+                    // 鏃犱汉瑙傜湅鍋滅敤
+                    result = true;
+                    // 淇敼鏁版嵁
+                    streamProxyService.stop(app, stream);
+                } else {
+                    // 鏃犱汉瑙傜湅涓嶅仛澶勭悊
+                    result = false;
                 }
             }
         }
-        return streamInfo;
-    }
-
-
-
-    @Override
-    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, boolean authority) {
-        return getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, null, authority);
-    }
-
-    @Override
-    public StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks, String addr, String callId, boolean isPlay) {
-        StreamInfo streamInfoResult = new StreamInfo();
-        streamInfoResult.setStream(stream);
-        streamInfoResult.setApp(app);
-        if (addr == null) {
-            addr = mediaInfo.getStreamIp();
-        }
-
-        streamInfoResult.setIp(addr);
-        streamInfoResult.setMediaServerId(mediaInfo.getId());
-        String callIdParam = ObjectUtils.isEmpty(callId)?"":"?callId=" + callId;
-        streamInfoResult.setRtmp(addr, mediaInfo.getRtmpPort(),mediaInfo.getRtmpSSlPort(), app,  stream, callIdParam);
-        streamInfoResult.setRtsp(addr, mediaInfo.getRtspPort(),mediaInfo.getRtspSSLPort(), app,  stream, callIdParam);
-        streamInfoResult.setFlv(addr, mediaInfo.getHttpPort(),mediaInfo.getHttpSSlPort(), app,  stream, callIdParam);
-        streamInfoResult.setFmp4(addr, mediaInfo.getHttpPort(),mediaInfo.getHttpSSlPort(), app,  stream, callIdParam);
-        streamInfoResult.setHls(addr, mediaInfo.getHttpPort(),mediaInfo.getHttpSSlPort(), app,  stream, callIdParam);
-        streamInfoResult.setTs(addr, mediaInfo.getHttpPort(),mediaInfo.getHttpSSlPort(), app,  stream, callIdParam);
-        streamInfoResult.setRtc(addr, mediaInfo.getHttpPort(),mediaInfo.getHttpSSlPort(), app,  stream, callIdParam, isPlay);
-
-        streamInfoResult.setTracks(tracks);
-        return streamInfoResult;
+        return result;
     }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
index 06c621e..aa39f41 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
@@ -1,10 +1,7 @@
 package com.genersoft.iot.vmp.service.impl;
 
-import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.common.InviteInfo;
-import com.genersoft.iot.vmp.common.InviteSessionStatus;
-import com.genersoft.iot.vmp.common.InviteSessionType;
 import com.baomidou.dynamic.datasource.annotation.DS;
+import com.genersoft.iot.vmp.common.*;
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
@@ -12,46 +9,38 @@
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
-import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
-import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
+import com.genersoft.iot.vmp.media.event.hook.HookData;
+import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent;
+import com.genersoft.iot.vmp.media.event.mediaServer.MediaSendRtpStoppedEvent;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.IInviteStreamService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IPlatformService;
 import com.genersoft.iot.vmp.service.IPlayService;
 import com.genersoft.iot.vmp.service.bean.*;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
-import com.genersoft.iot.vmp.storager.dao.*;
+import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
+import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
-import gov.nist.javax.sip.message.SIPRequest;
 import gov.nist.javax.sip.message.SIPResponse;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import javax.sdp.*;
 import javax.sip.InvalidArgumentException;
 import javax.sip.ResponseEvent;
-import javax.sip.PeerUnavailableException;
 import javax.sip.SipException;
 import java.text.ParseException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
 import java.util.*;
 
 /**
@@ -81,7 +70,7 @@
     private IMediaServerService mediaServerService;
 
     @Autowired
-    private SIPCommanderFroPlatform commanderForPlatform;
+    private ISIPCommanderForPlatform commanderForPlatform;
 
     @Autowired
     private DynamicTask dynamicTask;
@@ -99,11 +88,10 @@
     private UserSetting userSetting;
 
     @Autowired
-    private ZlmHttpHookSubscribe subscribe;
+    private HookSubscribe subscribe;
 
     @Autowired
     private VideoStreamSessionManager streamSession;
-
 
     @Autowired
     private IPlayService playService;
@@ -111,8 +99,56 @@
     @Autowired
     private IInviteStreamService inviteStreamService;
 
-    @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
+
+    /**
+     * 娴佺寮�鐨勫鐞�
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaDepartureEvent event) {
+        List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(event.getStream());
+        if (!sendRtpItems.isEmpty()) {
+            for (SendRtpItem sendRtpItem : sendRtpItems) {
+                if (sendRtpItem != null && sendRtpItem.getApp().equals(event.getApp())) {
+                    String platformId = sendRtpItem.getPlatformId();
+                    ParentPlatform platform = platformMapper.getParentPlatByServerGBId(platformId);
+
+                    try {
+                        if (platform != null) {
+                            commanderForPlatform.streamByeCmd(platform, sendRtpItem);
+                            redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(),
+                                    sendRtpItem.getCallId(), sendRtpItem.getStream());
+                        }
+                    } catch (SipException | InvalidArgumentException | ParseException e) {
+                        logger.error("[鍛戒护鍙戦�佸け璐 鍙戦�丅YE: {}", e.getMessage());
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * 鍙戞祦鍋滄
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaSendRtpStoppedEvent event) {
+        List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(event.getStream());
+        if (sendRtpItems != null && !sendRtpItems.isEmpty()) {
+            for (SendRtpItem sendRtpItem : sendRtpItems) {
+                ParentPlatform parentPlatform = platformMapper.getParentPlatByServerGBId(sendRtpItem.getPlatformId());
+                ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
+                try {
+                    commanderForPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
+                } catch (SipException | InvalidArgumentException | ParseException e) {
+                    logger.error("[鍛戒护鍙戦�佸け璐 鍥芥爣绾ц仈 鍙戦�丅YE: {}", e.getMessage());
+                }
+                redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
+                        sendRtpItem.getCallId(), sendRtpItem.getStream());
+            }
+        }
+    }
 
 
     @Override
@@ -400,7 +436,7 @@
             for (SendRtpItem sendRtpItem : sendRtpItems) {
                 ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
                 redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(), null, null);
-                MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+                MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
                 Map<String, Object> param = new HashMap<>(3);
                 param.put("vhost", "__defaultVhost__");
                 param.put("app", sendRtpItem.getApp());
@@ -463,7 +499,7 @@
     }
 
     @Override
-    public void broadcastInvite(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem, ZlmHttpHookSubscribe.Event hookEvent,
+    public void broadcastInvite(ParentPlatform platform, String channelId, MediaServer mediaServerItem, HookSubscribe.Event hookEvent,
                                 SipSubscribe.Event errorEvent, InviteTimeOutCallback timeoutCallback) throws InvalidArgumentException, ParseException, SipException {
 
         if (mediaServerItem == null) {
@@ -474,19 +510,19 @@
 
         if (inviteInfoForOld != null && inviteInfoForOld.getStreamInfo() != null) {
             // 濡傛灉zlm涓嶅瓨鍦ㄨ繖涓祦锛屽垯鍒犻櫎鏁版嵁鍗冲彲
-            MediaServerItem mediaServerItemForStreamInfo = mediaServerService.getOne(inviteInfoForOld.getStreamInfo().getMediaServerId());
+            MediaServer mediaServerItemForStreamInfo = mediaServerService.getOne(inviteInfoForOld.getStreamInfo().getMediaServerId());
             if (mediaServerItemForStreamInfo != null) {
-                Boolean ready = zlmServerFactory.isStreamReady(mediaServerItemForStreamInfo, inviteInfoForOld.getStreamInfo().getApp(), inviteInfoForOld.getStreamInfo().getStream());
+                Boolean ready = mediaServerService.isStreamReady(mediaServerItemForStreamInfo, inviteInfoForOld.getStreamInfo().getApp(), inviteInfoForOld.getStreamInfo().getStream());
                 if (!ready) {
                     // 閿欒瀛樺湪浜巖edis涓殑鏁版嵁
                     inviteStreamService.removeInviteInfo(inviteInfoForOld);
                 }else {
                     // 娴佺‘瀹炲皻鍦ㄦ帹娴侊紝鐩存帴鍥炶皟缁撴灉
-                    OnStreamChangedHookParam hookParam = new OnStreamChangedHookParam();
-                    hookParam.setApp(inviteInfoForOld.getStreamInfo().getApp());
-                    hookParam.setStream(inviteInfoForOld.getStreamInfo().getStream());
-
-                    hookEvent.response(mediaServerItemForStreamInfo, hookParam);
+                    HookData hookData = new HookData();
+                    hookData.setApp(inviteInfoForOld.getStreamInfo().getApp());
+                    hookData.setStream(inviteInfoForOld.getStreamInfo().getStream());
+                    hookData.setMediaServer(mediaServerItemForStreamInfo);
+                    hookEvent.response(hookData);
                     return;
                 }
             }
@@ -506,7 +542,7 @@
         } else {
             tcpMode = 0;
         }
-        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, ssrcCheck, false, null, true, false, tcpMode);
+        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, ssrcCheck, false, null, true, false, false, tcpMode);
         if (ssrcInfo == null || ssrcInfo.getPort() < 0) {
             logger.info("[鍥芥爣绾ц仈] 鍙戣捣璇煶鍠婅瘽 寮�鍚鍙g洃鍚け璐ワ紝 platform: {}, channel锛� {}", platform.getServerGBId(), channelId);
             SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>();
@@ -544,14 +580,14 @@
                 }
             }
         }, userSetting.getPlayTimeout());
-        commanderForPlatform.broadcastInviteCmd(platform, channelId, mediaServerItem, ssrcInfo, (mediaServerItemForInvite, hookParam)->{
+        commanderForPlatform.broadcastInviteCmd(platform, channelId, mediaServerItem, ssrcInfo, (hookData)->{
             logger.info("[鍥芥爣绾ц仈] 鍙戣捣璇煶鍠婅瘽 鏀跺埌涓婄骇鎺ㄦ祦 deviceId: {}, channelId: {}", platform.getServerGBId(), channelId);
             dynamicTask.stop(timeOutTaskKey);
             // hook鍝嶅簲
-            playService.onPublishHandlerForPlay(mediaServerItemForInvite, hookParam, platform.getServerGBId(), channelId);
+            playService.onPublishHandlerForPlay(hookData.getMediaServer(), hookData.getMediaInfo(), platform.getServerGBId(), channelId);
             // 鏀跺埌娴�
             if (hookEvent != null) {
-                hookEvent.response(mediaServerItem, hookParam);
+                hookEvent.response(hookData);
             }
         }, event -> {
 
@@ -604,13 +640,12 @@
         });
     }
 
-    private void inviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, int tcpMode, boolean ssrcCheck, MediaServerItem mediaServerItem,
+    private void inviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, int tcpMode, boolean ssrcCheck, MediaServer mediaServerItem,
                                  ParentPlatform platform, String channelId, String timeOutTaskKey, ErrorCallback<Object> callback,
                                  InviteInfo inviteInfo, InviteSessionType inviteSessionType){
         inviteInfo.setStatus(InviteSessionStatus.ok);
         ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
         String contentString = new String(responseEvent.getResponse().getRawContent());
-        System.out.println(1111);
         System.out.println(contentString);
         String ssrcInResponse = SipUtils.getSsrcFromSdp(contentString);
         // 鍏煎鍥炲鐨勬秷鎭腑缂哄皯ssrc(y瀛楁)鐨勬儏鍐�
@@ -709,7 +744,7 @@
 
 
     private void tcpActiveHandler(ParentPlatform platform, String channelId, String contentString,
-                                  MediaServerItem mediaServerItem, int tcpMode, boolean ssrcCheck,
+                                  MediaServer mediaServerItem, int tcpMode, boolean ssrcCheck,
                                   String timeOutTaskKey, SSRCInfo ssrcInfo, ErrorCallback<Object> callback){
         if (tcpMode != 2) {
             return;
@@ -737,8 +772,8 @@
             }
             logger.info("[TCP涓诲姩杩炴帴瀵规柟] serverGbId: {}, channelId: {}, 杩炴帴瀵规柟鐨勫湴鍧�锛歿}:{}, SSRC: {}, SSRC鏍¢獙锛歿}",
                     platform.getServerGBId(), channelId, sdp.getConnection().getAddress(), port, ssrcInfo.getSsrc(), ssrcCheck);
-            JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
-            logger.info("[TCP涓诲姩杩炴帴瀵规柟] 缁撴灉锛� {}", jsonObject);
+            Boolean result = mediaServerService.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
+            logger.info("[TCP涓诲姩杩炴帴瀵规柟] 缁撴灉锛� {}", result);
         } catch (SdpException e) {
             logger.error("[TCP涓诲姩杩炴帴瀵规柟] serverGbId: {}, channelId: {}, 瑙f瀽200OK鐨凷DP淇℃伅澶辫触", platform.getServerGBId(), channelId, e);
             dynamicTask.stop(timeOutTaskKey);
@@ -757,7 +792,7 @@
     }
 
     @Override
-    public void stopBroadcast(ParentPlatform platform, DeviceChannel channel, String stream, boolean sendBye, MediaServerItem mediaServerItem) {
+    public void stopBroadcast(ParentPlatform platform, DeviceChannel channel, String stream, boolean sendBye, MediaServer mediaServerItem) {
 
         try {
             if (sendBye) {
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 9bd0547..7406483 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -1,11 +1,9 @@
 package com.genersoft.iot.vmp.service.impl;
 
-import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.genersoft.iot.vmp.common.*;
 import com.genersoft.iot.vmp.conf.DynamicTask;
-import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.conf.exception.ServiceException;
@@ -18,17 +16,18 @@
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
+import com.genersoft.iot.vmp.media.bean.RecordInfo;
+import com.genersoft.iot.vmp.media.event.hook.Hook;
+import com.genersoft.iot.vmp.media.event.hook.HookType;
+import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
+import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent;
+import com.genersoft.iot.vmp.media.event.media.MediaNotFoundEvent;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
-import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRecordMp4;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.*;
 import com.genersoft.iot.vmp.service.bean.*;
 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
@@ -44,9 +43,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.util.ObjectUtils;
 
@@ -87,22 +85,13 @@
     private IRedisCatchStorage redisCatchStorage;
 
     @Autowired
-    private ZLMServerFactory zlmServerFactory;
-
-    @Autowired
     private IInviteStreamService inviteStreamService;
 
     @Autowired
-    private ZlmHttpHookSubscribe subscribe;
+    private HookSubscribe subscribe;
 
     @Autowired
     private SendRtpPortManager sendRtpPortManager;
-
-    @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
-
-    @Autowired
-    private IMediaService mediaService;
 
     @Autowired
     private IMediaServerService mediaServerService;
@@ -117,34 +106,164 @@
     private IDeviceChannelService channelService;
 
     @Autowired
-    private SipConfig sipConfig;
-
-    @Autowired
     private DynamicTask dynamicTask;
 
     @Autowired
     private ISIPCommanderForPlatform commanderForPlatform;
 
-
-    @Qualifier("taskExecutor")
-    @Autowired
-    private ThreadPoolTaskExecutor taskExecutor;
-
     @Autowired
     private RedisGbPlayMsgListener redisGbPlayMsgListener;
 
     @Autowired
-    private ZlmHttpHookSubscribe hookSubscribe;
-
-    @Autowired
     private SSRCFactory ssrcFactory;
 
-    @Autowired
-    private RedisTemplate<Object, Object> redisTemplate;
+    /**
+     * 娴佸埌鏉ョ殑澶勭悊
+     */
+    @Async("taskExecutor")
+    @org.springframework.context.event.EventListener
+    public void onApplicationEvent(MediaArrivalEvent event) {
+        if ("broadcast".equals(event.getApp())) {
+            if (event.getStream().indexOf("_") > 0) {
+                String[] streamArray = event.getStream().split("_");
+                if (streamArray.length == 2) {
+                    String deviceId = streamArray[0];
+                    String channelId = streamArray[1];
+                    Device device = deviceService.getDevice(deviceId);
+                    if (device == null) {
+                        logger.info("[璇煶瀵硅/鍠婅瘽] 鏈壘鍒拌澶囷細{}", deviceId);
+                        return;
+                    }
+                    if ("broadcast".equals(event.getApp())) {
+                        if (audioBroadcastManager.exit(deviceId, channelId)) {
+                            stopAudioBroadcast(deviceId, channelId);
+                        }
+                        // 寮�鍚闊冲璁查�氶亾
+                        try {
+                            audioBroadcastCmd(device, channelId, event.getMediaServer(),
+                                    event.getApp(), event.getStream(), 60, false, (msg) -> {
+                                        logger.info("[璇煶瀵硅] 閫氶亾寤虹珛鎴愬姛, device: {}, channel: {}", deviceId, channelId);
+                                    });
+                        } catch (InvalidArgumentException | ParseException | SipException e) {
+                            logger.error("[鍛戒护鍙戦�佸け璐 璇煶瀵硅: {}", e.getMessage());
+                        }
+                    }else if ("talk".equals(event.getApp())) {
+                        // 寮�鍚闊冲璁查�氶亾
+                        talkCmd(device, channelId, event.getMediaServer(), event.getStream(), (msg) -> {
+                            logger.info("[璇煶瀵硅] 閫氶亾寤虹珛鎴愬姛, device: {}, channel: {}", deviceId, channelId);
+                        });
+                    }
+                }
+            }
+        }
+
+
+    }
+
+    /**
+     * 娴佺寮�鐨勫鐞�
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaDepartureEvent event) {
+        List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(event.getStream());
+        if (!sendRtpItems.isEmpty()) {
+            for (SendRtpItem sendRtpItem : sendRtpItems) {
+                if (sendRtpItem != null && sendRtpItem.getApp().equals(event.getApp())) {
+                    String platformId = sendRtpItem.getPlatformId();
+                    Device device = deviceService.getDevice(platformId);
+                    try {
+                        if (device != null) {
+                            cmder.streamByeCmd(device, sendRtpItem.getChannelId(), event.getStream(), sendRtpItem.getCallId());
+                            if (sendRtpItem.getPlayType().equals(InviteStreamType.BROADCAST)
+                                    || sendRtpItem.getPlayType().equals(InviteStreamType.TALK)) {
+                                AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
+                                if (audioBroadcastCatch != null) {
+                                    // 鏉ヨ嚜涓婄骇骞冲彴鐨勫仠姝㈠璁�
+                                    logger.info("[鍋滄瀵硅] 鏉ヨ嚜涓婄骇锛屽钩鍙帮細{}, 閫氶亾锛歿}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
+                                    audioBroadcastManager.del(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
+                                }
+                            }
+                        }
+                    } catch (SipException | InvalidArgumentException | ParseException |
+                             SsrcTransactionNotFoundException e) {
+                        logger.error("[鍛戒护鍙戦�佸け璐 鍙戦�丅YE: {}", e.getMessage());
+                    }
+                }
+            }
+        }
+
+        if ("broadcast".equals(event.getApp()) || "talk".equals(event.getApp())) {
+            if (event.getStream().indexOf("_") > 0) {
+                String[] streamArray = event.getStream().split("_");
+                if (streamArray.length == 2) {
+                    String deviceId = streamArray[0];
+                    String channelId = streamArray[1];
+                    Device device = deviceService.getDevice(deviceId);
+                    if (device == null) {
+                        logger.info("[璇煶瀵硅/鍠婅瘽] 鏈壘鍒拌澶囷細{}", deviceId);
+                        return;
+                    }
+                    if ("broadcast".equals(event.getApp())) {
+                        stopAudioBroadcast(deviceId, channelId);
+                    }else if ("talk".equals(event.getApp())) {
+                        stopTalk(device, channelId, false);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 娴佹湭鎵惧埌鐨勫鐞�
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaNotFoundEvent event) {
+        if (!"rtp".equals(event.getApp())) {
+            return;
+        }
+        String[] s = event.getStream().split("_");
+        if ((s.length != 2 && s.length != 4)) {
+            return;
+        }
+        String deviceId = s[0];
+        String channelId = s[1];
+        Device device = redisCatchStorage.getDevice(deviceId);
+        if (device == null || !device.isOnLine()) {
+            return;
+        }
+        DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
+        if (deviceChannel == null) {
+            return;
+        }
+        if (s.length == 2) {
+            logger.info("[ZLM HOOK] 棰勮娴佹湭鎵惧埌, 鍙戣捣鑷姩鐐规挱锛歿}->{}->{}/{}", event.getMediaServer().getId(), event.getSchema(), event.getApp(), event.getStream());
+            play(event.getMediaServer(), deviceId, channelId, null, null);
+        } else if (s.length == 4) {
+            // 姝ゆ椂涓哄綍鍍忓洖鏀撅紝 褰曞儚鍥炴斁鏍煎紡涓�> 璁惧ID_閫氶亾ID_寮�濮嬫椂闂確缁撴潫鏃堕棿
+            String startTimeStr = s[2];
+            String endTimeStr = s[3];
+            if (startTimeStr == null || endTimeStr == null || startTimeStr.length() != 14 || endTimeStr.length() != 14) {
+                return;
+            }
+            String startTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(startTimeStr);
+            String endTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(endTimeStr);
+            logger.info("[ZLM HOOK] 鍥炴斁娴佹湭鎵惧埌, 鍙戣捣鑷姩鐐规挱锛歿}->{}->{}/{}-{}-{}",
+                    event.getMediaServer().getId(), event.getSchema(),
+                    event.getApp(), event.getStream(),
+                    startTime, endTime
+            );
+
+            SSRCInfo ssrcInfo = mediaServerService.openRTPServer(event.getMediaServer(), event.getStream(), null,
+                    device.isSsrcCheck(), true, 0, false, !deviceChannel.isHasAudio(), false, device.getStreamModeForParam());
+            playBack(event.getMediaServer(), ssrcInfo, deviceId, channelId, startTime, endTime, null);
+        }
+    }
 
 
     @Override
-    public SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback) {
+    public SSRCInfo play(MediaServer mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback) {
         if (mediaServerItem == null) {
             logger.warn("[鐐规挱] 鏈壘鍒板彲鐢ㄧ殑zlm deviceId: {},channelId:{}", deviceId, channelId);
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒板彲鐢ㄧ殑zlm");
@@ -179,9 +298,8 @@
                     return inviteInfo.getSsrcInfo();
                 }
                 String mediaServerId = streamInfo.getMediaServerId();
-                MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
-
-                Boolean ready = zlmServerFactory.isStreamReady(mediaInfo, "rtp", streamId);
+                MediaServer mediaInfo = mediaServerService.getOne(mediaServerId);
+                Boolean ready = mediaServerService.isStreamReady(mediaInfo, "rtp", streamId);
                 if (ready != null && ready) {
                     callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
                     inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
@@ -198,8 +316,8 @@
                 }
             }
         }
-        String streamId = String.format("%s_%s", device.getDeviceId(), channelId);;
-        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, ssrc, device.isSsrcCheck(),  false, 0, false, false, device.getStreamModeForParam());
+        String streamId = String.format("%s_%s", device.getDeviceId(), channelId);
+        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, ssrc, device.isSsrcCheck(),  false, 0, false, !channel.isHasAudio(), false, device.getStreamModeForParam());
         if (ssrcInfo == null) {
             callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getMsg(), null);
             inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
@@ -212,8 +330,8 @@
         return ssrcInfo;
     }
 
-    private void talk(MediaServerItem mediaServerItem, Device device, String channelId, String stream,
-                      ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
+    private void talk(MediaServer mediaServerItem, Device device, String channelId, String stream,
+                      HookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
                       Runnable timeoutCallback, AudioBroadcastEvent audioEvent) {
 
         String playSsrc = ssrcFactory.getPlaySsrc(mediaServerItem.getId());
@@ -269,38 +387,25 @@
             }
         }, userSetting.getPlayTimeout());
 
-        Map<String, Object> param = new HashMap<>(12);
-        param.put("vhost","__defaultVhost__");
-        param.put("app", sendRtpItem.getApp());
-        param.put("stream", sendRtpItem.getStream());
-        param.put("ssrc", sendRtpItem.getSsrc());
-        param.put("src_port", sendRtpItem.getLocalPort());
-        param.put("pt", sendRtpItem.getPt());
-        param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
-        param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
-        param.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");
-        param.put("recv_stream_id", sendRtpItem.getReceiveStream());
-        param.put("close_delay_ms", userSetting.getPlayTimeout() * 1000);
-
-        zlmServerFactory.startSendRtpPassive(mediaServerItem, param, jsonObject -> {
-            if (jsonObject == null || jsonObject.getInteger("code") != 0 ) {
-                mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
-                logger.info("[璇煶瀵硅]澶辫触 deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
-                audioEvent.call("澶辫触, " + jsonObject.getString("msg"));
-                // 鏌ョ湅鏄惁宸茬粡寤虹珛浜嗛�氶亾锛屽瓨鍦ㄥ垯鍙戦�乥ye
-                stopTalk(device, channelId);
-            }
-        });
+        try {
+            mediaServerService.startSendRtpPassive(mediaServerItem, null, sendRtpItem, userSetting.getPlayTimeout() * 1000);
+        }catch (ControllerException e) {
+            mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
+            logger.info("[璇煶瀵硅]澶辫触 deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
+            audioEvent.call("澶辫触, " + e.getMessage());
+            // 鏌ョ湅鏄惁宸茬粡寤虹珛浜嗛�氶亾锛屽瓨鍦ㄥ垯鍙戦�乥ye
+            stopTalk(device, channelId);
+        }
 
 
         // 鏌ョ湅璁惧鏄惁宸茬粡鍦ㄦ帹娴�
         try {
-            cmder.talkStreamCmd(mediaServerItem, sendRtpItem, device, channelId, callId, (mediaServerItemInuse, hookParam) -> {
-                logger.info("[璇煶瀵硅] 娴佸凡鐢熸垚锛� 寮�濮嬫帹娴侊細 " + hookParam);
+            cmder.talkStreamCmd(mediaServerItem, sendRtpItem, device, channelId, callId, (hookData) -> {
+                logger.info("[璇煶瀵硅] 娴佸凡鐢熸垚锛� 寮�濮嬫帹娴侊細 " + hookData);
                 dynamicTask.stop(timeOutTaskKey);
                 // TODO 鏆備笉鍋氬鐞�
-            }, (mediaServerItemInuse, hookParam) -> {
-                logger.info("[璇煶瀵硅] 璁惧寮�濮嬫帹娴侊細 " + hookParam);
+            }, (hookData) -> {
+                logger.info("[璇煶瀵硅] 璁惧寮�濮嬫帹娴侊細 " + hookData);
                 dynamicTask.stop(timeOutTaskKey);
 
             }, (event) -> {
@@ -355,7 +460,7 @@
 
 
     @Override
-    public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel,
+    public void play(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel,
                      ErrorCallback<Object> callback) {
 
         if (mediaServerItem == null || ssrcInfo == null) {
@@ -410,8 +515,7 @@
                     streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
                     mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
                     // 鍙栨秷璁㈤槄娑堟伅鐩戝惉
-                    HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
-                    subscribe.removeSubscribe(hookSubscribe);
+                    subscribe.removeSubscribe(Hook.getInstance(HookType.on_media_arrival, "rtp", ssrcInfo.getStream(), mediaServerItem.getId()));
                 }
             }else {
                 logger.info("[鐐规挱瓒呮椂] 鏀舵祦瓒呮椂 deviceId: {}, channelId: {},鐮佹祦锛歿}锛岀鍙o細{}, SSRC: {}",
@@ -426,11 +530,11 @@
         }, userSetting.getPlayTimeout());
 
         try {
-            cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channel, (mediaServerItemInuse, hookParam ) -> {
-                logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + hookParam);
+            cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channel, (hookData ) -> {
+                logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + hookData);
                 dynamicTask.stop(timeOutTaskKey);
                 // hook鍝嶅簲
-                StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInuse, hookParam, device.getDeviceId(), channel.getChannelId());
+                StreamInfo streamInfo = onPublishHandlerForPlay(hookData.getMediaServer(), hookData.getMediaInfo(), device.getDeviceId(), channel.getChannelId());
                 if (streamInfo == null){
                     callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
                             InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
@@ -446,7 +550,7 @@
                         streamInfo);
                 logger.info("[鐐规挱鎴愬姛] deviceId: {}, channelId:{}, 鐮佹祦绫诲瀷锛歿}", device.getDeviceId(), channel.getChannelId(),
                         channel.getStreamIdentification());
-                snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
+                snapOnPlay(hookData.getMediaServer(), device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
             }, (eventResult) -> {
                 // 澶勭悊鏀跺埌200ok鍚庣殑TCP涓诲姩杩炴帴浠ュ強SSRC涓嶄竴鑷寸殑闂
                 InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channel.getChannelId(),
@@ -460,8 +564,7 @@
 
                 streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
 
-                callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_ERROR.getCode(),
-                        String.format("鐐规挱澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg), null);
+                callback.run(event.statusCode, event.msg, null);
                 inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null,
                         InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
                         String.format("鐐规挱澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg), null);
@@ -489,7 +592,7 @@
     }
 
     private void tcpActiveHandler(Device device, String channelId, String contentString,
-                                  MediaServerItem mediaServerItem,
+                                  MediaServer mediaServerItem,
                                   String timeOutTaskKey, SSRCInfo ssrcInfo, ErrorCallback<Object> callback){
         if (!device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
             return;
@@ -516,9 +619,9 @@
                 }
             }
             logger.info("[TCP涓诲姩杩炴帴瀵规柟] deviceId: {}, channelId: {}, 杩炴帴瀵规柟鐨勫湴鍧�锛歿}:{}, 鏀舵祦妯″紡锛歿}, SSRC: {}, SSRC鏍¢獙锛歿}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
-            JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
-            logger.info("[TCP涓诲姩杩炴帴瀵规柟] 缁撴灉锛� {}" , jsonObject);
-            if (jsonObject.getInteger("code") != 0) {
+            Boolean result = mediaServerService.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
+            logger.info("[TCP涓诲姩杩炴帴瀵规柟] 缁撴灉锛� {}" , result);
+            if (!result) {
                 // 涓诲姩杩炴帴澶辫触锛岀粨鏉熸祦绋嬶紝 娓呯悊鏁版嵁
                 dynamicTask.stop(timeOutTaskKey);
                 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
@@ -558,7 +661,7 @@
      * @param channelId            閫氶亾 ID
      * @param stream               ssrc
      */
-    private void snapOnPlay(MediaServerItem mediaServerItemInuse, String deviceId, String channelId, String stream) {
+    private void snapOnPlay(MediaServer mediaServerItemInuse, String deviceId, String channelId, String stream) {
         String streamUrl;
         if (mediaServerItemInuse.getRtspPort() != 0) {
             streamUrl = String.format("rtsp://127.0.0.1:%s/%s/%s", mediaServerItemInuse.getRtspPort(), "rtp", stream);
@@ -569,14 +672,13 @@
         String fileName = deviceId + "_" + channelId + ".jpg";
         // 璇锋眰鎴浘
         logger.info("[璇锋眰鎴浘]: " + fileName);
-        zlmresTfulUtils.getSnap(mediaServerItemInuse, streamUrl, 15, 1, path, fileName);
+        mediaServerService.getSnap(mediaServerItemInuse, streamUrl, 15, 1, path, fileName);
     }
 
-    public StreamInfo onPublishHandlerForPlay(MediaServerItem mediaServerItem, HookParam hookParam, String deviceId, String channelId) {
+    public StreamInfo onPublishHandlerForPlay(MediaServer mediaServerItem, MediaInfo mediaInfo, String deviceId, String channelId) {
         StreamInfo streamInfo = null;
         Device device = redisCatchStorage.getDevice(deviceId);
-        OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam)hookParam;
-        streamInfo = onPublishHandler(mediaServerItem, streamChangedHookParam, deviceId, channelId);
+        streamInfo = onPublishHandler(mediaServerItem, mediaInfo, deviceId, channelId);
         if (streamInfo != null) {
             DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
             if (deviceChannel != null) {
@@ -594,9 +696,8 @@
 
     }
 
-    private StreamInfo onPublishHandlerForPlayback(MediaServerItem mediaServerItem, HookParam param, String deviceId, String channelId, String startTime, String endTime) {
-        OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam) param;
-        StreamInfo streamInfo = onPublishHandler(mediaServerItem, streamChangedHookParam, deviceId, channelId);
+    private StreamInfo onPublishHandlerForPlayback(MediaServer mediaServerItem, MediaInfo mediaInfo, String deviceId, String channelId, String startTime, String endTime) {
+        StreamInfo streamInfo = onPublishHandler(mediaServerItem, mediaInfo, deviceId, channelId);
         if (streamInfo != null) {
             streamInfo.setStartTime(startTime);
             streamInfo.setEndTime(endTime);
@@ -605,7 +706,7 @@
                 deviceChannel.setStreamId(streamInfo.getStream());
                 storager.startPlay(deviceId, channelId, streamInfo.getStream());
             }
-            InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, ((OnStreamChangedHookParam) param).getStream());
+            InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, mediaInfo.getStream());
             if (inviteInfo != null) {
                 inviteInfo.setStatus(InviteSessionStatus.ok);
 
@@ -618,11 +719,11 @@
     }
 
     @Override
-    public MediaServerItem getNewMediaServerItem(Device device) {
+    public MediaServer getNewMediaServerItem(Device device) {
         if (device == null) {
             return null;
         }
-        MediaServerItem mediaServerItem;
+        MediaServer mediaServerItem;
         if (ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) {
             mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(null);
         } else {
@@ -643,7 +744,13 @@
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒拌澶囷細" + deviceId);
         }
 
-        MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
+        DeviceChannel channel = channelService.getOne(deviceId, channelId);
+        if (channel == null) {
+            logger.warn("[褰曞儚鍥炴斁] 鏈壘鍒伴�氶亾 deviceId: {},channelId:{}", deviceId, channelId);
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒伴�氶亾锛�" + channelId);
+        }
+
+        MediaServer newMediaServerItem = getNewMediaServerItem(device);
         if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE") && ! newMediaServerItem.isRtpEnable()) {
             logger.warn("[褰曞儚鍥炴斁] 鍗曠鍙f敹娴佹椂涓嶆敮鎸乀CP涓诲姩鏂瑰紡鏀舵祦 deviceId: {},channelId:{}", deviceId, channelId);
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "鍗曠鍙f敹娴佹椂涓嶆敮鎸乀CP涓诲姩鏂瑰紡鏀舵祦");
@@ -655,12 +762,12 @@
                 .replace(":", "")
                 .replace(" ", "");
         String stream = deviceId + "_" + channelId + "_" + startTimeStr + "_" + endTimeTimeStr;
-        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, stream, null, device.isSsrcCheck(),  true, 0, false,  false, device.getStreamModeForParam());
+        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, stream, null, device.isSsrcCheck(),  true, 0, false,  !channel.isHasAudio(),  false, device.getStreamModeForParam());
         playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, callback);
     }
 
     @Override
-    public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
+    public void playBack(MediaServer mediaServerItem, SSRCInfo ssrcInfo,
                          String deviceId, String channelId, String startTime,
                          String endTime, ErrorCallback<Object> callback) {
         if (mediaServerItem == null || ssrcInfo == null) {
@@ -711,10 +818,10 @@
             inviteStreamService.removeInviteInfo(inviteInfo);
         };
 
-        ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, hookParam) -> {
-            logger.info("鏀跺埌鍥炴斁璁㈤槄娑堟伅锛� " + hookParam);
+        HookSubscribe.Event hookEvent = (hookData) -> {
+            logger.info("鏀跺埌鍥炴斁璁㈤槄娑堟伅锛� " + hookData);
             dynamicTask.stop(playBackTimeOutTaskKey);
-            StreamInfo streamInfo = onPublishHandlerForPlayback(mediaServerItemInuse, hookParam, deviceId, channelId, startTime, endTime);
+            StreamInfo streamInfo = onPublishHandlerForPlayback(hookData.getMediaServer(), hookData.getMediaInfo(), deviceId, channelId, startTime, endTime);
             if (streamInfo == null) {
                 logger.warn("璁惧鍥炴斁API璋冪敤澶辫触锛�");
                 callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
@@ -744,7 +851,7 @@
     }
 
 
-    private void InviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, MediaServerItem mediaServerItem,
+    private void InviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, MediaServer mediaServerItem,
                                  Device device, String channelId, String timeOutTaskKey, ErrorCallback<Object> callback,
                                  InviteInfo inviteInfo, InviteSessionType inviteSessionType){
         inviteInfo.setStatus(InviteSessionStatus.ok);
@@ -840,7 +947,11 @@
         if (device == null) {
             return;
         }
-        MediaServerItem newMediaServerItem = this.getNewMediaServerItem(device);
+        DeviceChannel channel = channelService.getOne(deviceId, channelId);
+        if (channel == null) {
+            return;
+        }
+        MediaServer newMediaServerItem = this.getNewMediaServerItem(device);
         if (newMediaServerItem == null) {
             callback.run(InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getCode(),
                     InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getMsg(),
@@ -848,13 +959,13 @@
             return;
         }
         // 褰曞儚涓嬭浇涓嶄娇鐢ㄥ浐瀹氭祦鍦板潃锛屽浐瀹氭祦鍦板潃浼氬鑷村鏋滃紑濮嬫椂闂翠笌缁撴潫鏃堕棿涓�鑷存椂鏂囦欢閿欒鐨勫彔鍔犲湪涓�璧�
-        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(),  true, 0, false,false, device.getStreamModeForParam());
+        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(),  true, 0, false,!channel.isHasAudio(), false, device.getStreamModeForParam());
         download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, callback);
     }
 
 
     @Override
-    public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) {
+    public void download(MediaServer mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) {
         if (mediaServerItem == null || ssrcInfo == null) {
             callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
                     InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
@@ -900,10 +1011,10 @@
             streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
             inviteStreamService.removeInviteInfo(inviteInfo);
         };
-        ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, hookParam) -> {
-            logger.info("[褰曞儚涓嬭浇]鏀跺埌璁㈤槄娑堟伅锛� " + hookParam);
+        HookSubscribe.Event hookEvent = (hookData) -> {
+            logger.info("[褰曞儚涓嬭浇]鏀跺埌璁㈤槄娑堟伅锛� " + hookData);
             dynamicTask.stop(downLoadTimeOutTaskKey);
-            StreamInfo streamInfo = onPublishHandlerForDownload(mediaServerItemInuse, hookParam, deviceId, channelId, startTime, endTime);
+            StreamInfo streamInfo = onPublishHandlerForDownload(hookData.getMediaServer(), hookData.getMediaInfo(), deviceId, channelId, startTime, endTime);
             if (streamInfo == null) {
                 logger.warn("[褰曞儚涓嬭浇] 鑾峰彇娴佸湴鍧�淇℃伅澶辫触");
                 callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
@@ -921,26 +1032,24 @@
                                 downLoadTimeOutTaskKey, callback, inviteInfo, InviteSessionType.DOWNLOAD);
 
                         // 娉ㄥ唽褰曞儚鍥炶皟浜嬩欢锛屽綍鍍忎笅杞界粨鏉熷悗鍐欏叆涓嬭浇鍦板潃
-                        ZlmHttpHookSubscribe.Event hookEventForRecord = (mediaServerItemInuse, hookParam) -> {
+                        HookSubscribe.Event hookEventForRecord = (hookData) -> {
                             logger.info("[褰曞儚涓嬭浇] 鏀跺埌褰曞儚鍐欏叆纾佺洏娑堟伅锛� 锛� {}/{}-{}",
                                     inviteInfo.getDeviceId(), inviteInfo.getChannelId(), ssrcInfo.getStream());
-                            logger.info("[褰曞儚涓嬭浇] 鏀跺埌褰曞儚鍐欏叆纾佺洏娑堟伅鍐呭锛� " + hookParam);
-                            OnRecordMp4HookParam recordMp4HookParam = (OnRecordMp4HookParam)hookParam;
-                            String filePath = recordMp4HookParam.getFile_path();
+                            logger.info("[褰曞儚涓嬭浇] 鏀跺埌褰曞儚鍐欏叆纾佺洏娑堟伅鍐呭锛� " + hookData);
+                            RecordInfo recordInfo = hookData.getRecordInfo();
+                            String filePath = recordInfo.getFilePath();
                             DownloadFileInfo downloadFileInfo = CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath);
                             InviteInfo inviteInfoForNew = inviteStreamService.getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId()
                                     , inviteInfo.getChannelId(), inviteInfo.getStream());
                             inviteInfoForNew.getStreamInfo().setDownLoadFilePath(downloadFileInfo);
                             inviteStreamService.updateInviteInfo(inviteInfoForNew);
                         };
-                        HookSubscribeForRecordMp4 hookSubscribe = HookSubscribeFactory.on_record_mp4(
-                                mediaServerItem.getId(), "rtp", ssrcInfo.getStream());
-
+                        Hook hook = Hook.getInstance(HookType.on_record_mp4, "rtp", ssrcInfo.getStream(), mediaServerItem.getId());
                         // 璁剧疆杩囨湡鏃堕棿锛屼笅杞藉け璐ユ椂鑷姩澶勭悊璁㈤槄鏁版嵁
 //                        long difference = DateUtil.getDifference(startTime, endTime)/1000;
 //                        Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.MINUTES.toSeconds(difference * 2));
 //                        hookSubscribe.setExpires(expiresInstant);
-                        subscribe.addSubscribe(hookSubscribe, hookEventForRecord);
+                        subscribe.addSubscribe(hook, hookEventForRecord);
                     });
         } catch (InvalidArgumentException | SipException | ParseException e) {
             logger.error("[鍛戒护鍙戦�佸け璐 褰曞儚涓嬭浇: {}", e.getMessage());
@@ -967,7 +1076,7 @@
 
         // 鑾峰彇褰撳墠宸蹭笅杞芥椂闀�
         String mediaServerId = inviteInfo.getStreamInfo().getMediaServerId();
-        MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
+        MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId);
         if (mediaServerItem == null) {
             logger.warn("[鑾峰彇涓嬭浇杩涘害] 鏌ヨ褰曞儚淇℃伅鏃跺彂鐜拌妭鐐逛笉瀛樺湪");
             return null;
@@ -978,30 +1087,13 @@
             logger.warn("[鑾峰彇涓嬭浇杩涘害] 涓嬭浇宸茬粨鏉�");
             return null;
         }
-
-        JSONObject mediaListJson= zlmresTfulUtils.getMediaList(mediaServerItem, "rtp", stream);
-        if (mediaListJson == null) {
-            logger.warn("[鑾峰彇涓嬭浇杩涘害] 浠巣lm鏌ヨ杩涘害澶辫触");
+        String app = "rtp";
+        MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServerItem, app, stream);
+        if (mediaInfo == null) {
+            logger.warn("[鑾峰彇涓嬭浇杩涘害] 鏌ヨ杩涘害澶辫触, 鑺傜偣Id锛� {}锛� {}/{}", mediaServerId, app, stream);
             return null;
         }
-        if (mediaListJson.getInteger("code") != 0) {
-            logger.warn("[鑾峰彇涓嬭浇杩涘害] 浠巣lm鏌ヨ杩涘害鍑虹幇閿欒锛� {}", mediaListJson.getString("msg"));
-            return null;
-        }
-        JSONArray data = mediaListJson.getJSONArray("data");
-        if (data == null) {
-            logger.warn("[鑾峰彇涓嬭浇杩涘害] 浠巣lm鏌ヨ杩涘害鏃舵湭杩斿洖鏁版嵁");
-            return null;
-        }
-        JSONObject mediaJSON = data.getJSONObject(0);
-        JSONArray tracks = mediaJSON.getJSONArray("tracks");
-        if (tracks.isEmpty()) {
-            logger.warn("[鑾峰彇涓嬭浇杩涘害] 浠巣lm鏌ヨ杩涘害鏃舵湭杩斿洖鏁版嵁");
-            return null;
-        }
-        JSONObject jsonObject = tracks.getJSONObject(0);
-        long duration = jsonObject.getLongValue("duration");
-        if (duration == 0) {
+        if (mediaInfo.getDuration() == 0) {
             inviteInfo.getStreamInfo().setProgress(0);
         } else {
             String startTime = inviteInfo.getStreamInfo().getStartTime();
@@ -1010,7 +1102,7 @@
             long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
             long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
 
-            BigDecimal currentCount = new BigDecimal(duration);
+            BigDecimal currentCount = new BigDecimal(mediaInfo.getDuration());
             BigDecimal totalCount = new BigDecimal((end - start) * 1000);
             BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP);
             double process = divide.doubleValue();
@@ -1023,9 +1115,8 @@
         return inviteInfo.getStreamInfo();
     }
 
-    private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, HookParam hookParam, String deviceId, String channelId, String startTime, String endTime) {
-        OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam) hookParam;
-        StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, streamChangedHookParam, deviceId, channelId);
+    private StreamInfo onPublishHandlerForDownload(MediaServer mediaServerItemInuse, MediaInfo mediaInfo, String deviceId, String channelId, String startTime, String endTime) {
+        StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, mediaInfo, deviceId, channelId);
         if (streamInfo != null) {
             streamInfo.setProgress(0);
             streamInfo.setStartTime(startTime);
@@ -1042,8 +1133,8 @@
     }
 
 
-    public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, OnStreamChangedHookParam hookParam, String deviceId, String channelId) {
-        StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem, "rtp", hookParam.getStream(), hookParam.getTracks(), null);
+    public StreamInfo onPublishHandler(MediaServer mediaServerItem, MediaInfo mediaInfo, String deviceId, String channelId) {
+        StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, "rtp", mediaInfo.getStream(), mediaInfo, null);
         streamInfo.setDeviceID(deviceId);
         streamInfo.setChannelId(channelId);
         return streamInfo;
@@ -1099,7 +1190,7 @@
             logger.warn("寮�鍚闊冲箍鎾殑鏃跺�欐湭鎵惧埌閫氶亾锛� {}", channelId);
             return null;
         }
-        MediaServerItem mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(null);
+        MediaServer mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(null);
         if (broadcastMode == null) {
             broadcastMode = true;
         }
@@ -1108,13 +1199,13 @@
         AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult();
         audioBroadcastResult.setApp(app);
         audioBroadcastResult.setStream(stream);
-        audioBroadcastResult.setStreamInfo(new StreamContent(mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, stream, null, null, null, false)));
+        audioBroadcastResult.setStreamInfo(new StreamContent(mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, app, stream, null, null, null, false)));
         audioBroadcastResult.setCodec("G.711");
         return audioBroadcastResult;
     }
 
     @Override
-    public boolean audioBroadcastCmd(Device device, String channelId, MediaServerItem mediaServerItem, String app, String stream, int timeout, boolean isFromPlatform, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException {
+    public boolean audioBroadcastCmd(Device device, String channelId, MediaServer mediaServerItem, String app, String stream, int timeout, boolean isFromPlatform, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException {
         if (device == null || channelId == null) {
             return false;
         }
@@ -1130,7 +1221,7 @@
             SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
             if (sendRtpItem != null && sendRtpItem.isOnlyAudio()) {
                 // 鏌ヨ娴佹槸鍚﹀瓨鍦紝涓嶅瓨鍦ㄥ垯璁や负鏄紓甯哥姸鎬�
-                Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, sendRtpItem.getApp(), sendRtpItem.getStream());
+                Boolean streamReady = mediaServerService.isStreamReady(mediaServerItem, sendRtpItem.getApp(), sendRtpItem.getStream());
                 if (streamReady) {
                     logger.warn("璇煶骞挎挱宸茬粡寮�鍚細 {}", channelId);
                     event.call("璇煶骞挎挱宸茬粡寮�鍚�");
@@ -1140,18 +1231,6 @@
                 }
             }
         }
-//        SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
-//        if (sendRtpItem != null) {
-//            MediaServerItem mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
-//            Boolean streamReady = zlmServerFactory.isStreamReady(mediaServer, sendRtpItem.getApp(), sendRtpItem.getStream());
-//            if (streamReady) {
-//                logger.warn("[璇煶瀵硅] 杩涜涓細 {}", channelId);
-//                event.call("璇煶瀵硅杩涜涓�");
-//                return false;
-//            } else {
-//                stopTalk(device, channelId);
-//            }
-//        }
 
         // 鍙戦�侀�氱煡
         cmder.audioBroadcastCmd(device, channelId, eventResultForOk -> {
@@ -1182,8 +1261,8 @@
             SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
             if (sendRtpItem != null && sendRtpItem.isOnlyAudio()) {
                 // 鏌ヨ娴佹槸鍚﹀瓨鍦紝涓嶅瓨鍦ㄥ垯璁や负鏄紓甯哥姸鎬�
-                MediaServerItem mediaServerServiceOne = mediaServerService.getOne(sendRtpItem.getMediaServerId());
-                Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerServiceOne, sendRtpItem.getApp(), sendRtpItem.getStream());
+                MediaServer mediaServerServiceOne = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+                Boolean streamReady = mediaServerService.isStreamReady(mediaServerServiceOne, sendRtpItem.getApp(), sendRtpItem.getStream());
                 if (streamReady) {
                     logger.warn("璇煶骞挎挱閫氶亾浣跨敤涓細 {}", channelId);
                     return true;
@@ -1212,12 +1291,8 @@
                 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(deviceId, audioBroadcastCatch.getChannelId(), null, null);
                 if (sendRtpItem != null) {
                     redisCatchStorage.deleteSendRTPServer(deviceId, sendRtpItem.getChannelId(), null, null);
-                    MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
-                    Map<String, Object> param = new HashMap<>();
-                    param.put("vhost", "__defaultVhost__");
-                    param.put("app", sendRtpItem.getApp());
-                    param.put("stream", sendRtpItem.getStream());
-                    zlmresTfulUtils.stopSendRtp(mediaInfo, param);
+                    MediaServer mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+                    mediaServerService.stopSendRtp(mediaServer, sendRtpItem.getApp(), sendRtpItem.getStream(), null);
                     try {
                         cmder.streamByeCmdForDeviceInvite(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null);
                     } catch (InvalidArgumentException | ParseException | SipException |
@@ -1293,7 +1368,7 @@
         }
         inviteInfo.getStreamInfo().setPause(true);
         inviteStreamService.updateInviteInfo(inviteInfo);
-        MediaServerItem mediaServerItem = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
+        MediaServer mediaServerItem = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
         if (null == mediaServerItem) {
             logger.warn("mediaServer 涓嶅瓨鍦�!");
             throw new ServiceException("mediaServer涓嶅瓨鍦�");
@@ -1304,8 +1379,8 @@
         if (!mediaServerItem.isRtpEnable()) {
             streamKey = Long.toHexString(Long.parseLong(inviteInfo.getSsrcInfo().getSsrc())).toUpperCase();
         }
-        JSONObject jsonObject = zlmresTfulUtils.pauseRtpCheck(mediaServerItem, streamKey);
-        if (jsonObject == null || jsonObject.getInteger("code") != 0) {
+        Boolean result = mediaServerService.pauseRtpCheck(mediaServerItem, streamKey);
+        if (!result) {
             throw new ServiceException("鏆傚仠RTP鎺ユ敹澶辫触");
         }
         Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
@@ -1321,7 +1396,7 @@
         }
         inviteInfo.getStreamInfo().setPause(false);
         inviteStreamService.updateInviteInfo(inviteInfo);
-        MediaServerItem mediaServerItem = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
+        MediaServer mediaServerItem = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
         if (null == mediaServerItem) {
             logger.warn("mediaServer 涓嶅瓨鍦�!");
             throw new ServiceException("mediaServer涓嶅瓨鍦�");
@@ -1332,8 +1407,8 @@
         if (!mediaServerItem.isRtpEnable()) {
             streamKey = Long.toHexString(Long.parseLong(inviteInfo.getSsrcInfo().getSsrc())).toUpperCase();
         }
-        JSONObject jsonObject = zlmresTfulUtils.resumeRtpCheck(mediaServerItem, streamKey);
-        if (jsonObject == null || jsonObject.getInteger("code") != 0) {
+        boolean result = mediaServerService.resumeRtpCheck(mediaServerItem, streamKey);
+        if (!result) {
             throw new ServiceException("缁х画RTP鎺ユ敹澶辫触");
         }
         Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
@@ -1343,24 +1418,7 @@
     @Override
     public void startPushStream(SendRtpItem sendRtpItem, SIPResponse sipResponse, ParentPlatform platform, CallIdHeader callIdHeader) {
         // 寮�濮嬪彂娴�
-        String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
-        MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
-        logger.info("[寮�濮嬫帹娴乚 rtp/{}, 鐩爣={}:{}锛孲SRC={}, RTCP={}", sendRtpItem.getStream(),
-                sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
-        Map<String, Object> param = new HashMap<>(12);
-        param.put("vhost", "__defaultVhost__");
-        param.put("app", sendRtpItem.getApp());
-        param.put("stream", sendRtpItem.getStream());
-        param.put("ssrc", sendRtpItem.getSsrc());
-        param.put("src_port", sendRtpItem.getLocalPort());
-        param.put("pt", sendRtpItem.getPt());
-        param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
-        param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
-        param.put("is_udp", is_Udp);
-        if (!sendRtpItem.isTcp()) {
-            // udp妯″紡涓嬪紑鍚痳tcp淇濇椿
-            param.put("udp_rtcp_timeout", sendRtpItem.isRtcp() ? "1" : "0");
-        }
+        MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
 
         if (mediaInfo == null) {
             RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
@@ -1368,80 +1426,55 @@
                     sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),
                     sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());
             redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> {
-                startSendRtpStreamHand(sendRtpItem, platform, json, param, callIdHeader);
+                startSendRtpStreamFailHand(sendRtpItem, platform, callIdHeader);
             });
         } else {
-            // 濡傛灉鏄弗鏍兼ā寮忥紝闇�瑕佸叧闂鍙e崰鐢�
-            JSONObject startSendRtpStreamResult = null;
-            if (sendRtpItem.getLocalPort() != 0) {
+            try {
                 if (sendRtpItem.isTcpActive()) {
-                    startSendRtpStreamResult = zlmServerFactory.startSendRtpPassive(mediaInfo, param);
+                    mediaServerService.startSendRtpPassive(mediaInfo, platform, sendRtpItem, null);
                 } else {
-                    param.put("dst_url", sendRtpItem.getIp());
-                    param.put("dst_port", sendRtpItem.getPort());
-                    startSendRtpStreamResult = zlmServerFactory.startSendRtpStream(mediaInfo, param);
+                    mediaServerService.startSendRtpStream(mediaInfo, platform, sendRtpItem);
                 }
-            } else {
-                if (sendRtpItem.isTcpActive()) {
-                    startSendRtpStreamResult = zlmServerFactory.startSendRtpPassive(mediaInfo, param);
-                } else {
-                    param.put("dst_url", sendRtpItem.getIp());
-                    param.put("dst_port", sendRtpItem.getPort());
-                    startSendRtpStreamResult = zlmServerFactory.startSendRtpStream(mediaInfo, param);
-                }
+            }catch (ControllerException e) {
+                logger.error("RTP鎺ㄦ祦澶辫触: {}", e.getMessage());
+                startSendRtpStreamFailHand(sendRtpItem, platform, callIdHeader);
+                return;
             }
-            if (startSendRtpStreamResult != null) {
-                startSendRtpStreamHand(sendRtpItem, platform, startSendRtpStreamResult, param, callIdHeader);
-            }
+
+            logger.info("RTP鎺ㄦ祦鎴愬姛[ {}/{} ]锛寋}, ", sendRtpItem.getApp(), sendRtpItem.getStream(),
+                    sendRtpItem.isTcpActive()?"琚姩鍙戞祦": sendRtpItem.getIp() + ":" + sendRtpItem.getPort());
+
         }
     }
 
     @Override
-    public void startSendRtpStreamHand(SendRtpItem sendRtpItem, Object correlationInfo,
-                                       JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader) {
-        if (jsonObject == null) {
-            logger.error("RTP鎺ㄦ祦澶辫触: 璇锋鏌LM鏈嶅姟");
-        } else if (jsonObject.getInteger("code") == 0) {
-            logger.info("璋冪敤ZLM鎺ㄦ祦鎺ュ彛, 缁撴灉锛� {}", jsonObject);
-            logger.info("RTP鎺ㄦ祦鎴愬姛[ {}/{} ]锛寋}->{}, ", param.get("app"), param.get("stream"), jsonObject.getString("local_port"),
-                    sendRtpItem.isTcpActive()?"琚姩鍙戞祦": param.get("dst_url") + ":" + param.get("dst_port"));
-            if (sendRtpItem.getPlayType() == InviteStreamType.PUSH && correlationInfo instanceof ParentPlatform) {
-                ParentPlatform platform = (ParentPlatform)correlationInfo;
-                MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, sendRtpItem.getApp(), sendRtpItem.getStream(),
-                        sendRtpItem.getChannelId(), platform.getServerGBId(), platform.getName(), userSetting.getServerId(),
-                        sendRtpItem.getMediaServerId());
-                messageForPushChannel.setPlatFormIndex(platform.getId());
-                redisCatchStorage.sendPlatformStartPlayMsg(messageForPushChannel);
+    public void startSendRtpStreamFailHand(SendRtpItem sendRtpItem, ParentPlatform platform, CallIdHeader callIdHeader) {
+        if (sendRtpItem.isOnlyAudio()) {
+            Device device = deviceService.getDevice(sendRtpItem.getDeviceId());
+            AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
+            if (audioBroadcastCatch != null) {
+                try {
+                    cmder.streamByeCmd(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null);
+                } catch (SipException | ParseException | InvalidArgumentException |
+                         SsrcTransactionNotFoundException exception) {
+                    logger.error("[鍛戒护鍙戦�佸け璐 鍋滄璇煶瀵硅: {}", exception.getMessage());
+                }
             }
         } else {
-            logger.error("RTP鎺ㄦ祦澶辫触: {}, 鍙傛暟锛歿}", jsonObject.getString("msg"), JSONObject.toJSONString(param));
-            if (sendRtpItem.isOnlyAudio()) {
-                Device device = deviceService.getDevice(sendRtpItem.getDeviceId());
-                AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
-                if (audioBroadcastCatch != null) {
-                    try {
-                        cmder.streamByeCmd(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null);
-                    } catch (SipException | ParseException | InvalidArgumentException |
-                             SsrcTransactionNotFoundException e) {
-                        logger.error("[鍛戒护鍙戦�佸け璐 鍋滄璇煶瀵硅: {}", e.getMessage());
-                    }
-                }
-            } else {
+            if (platform != null) {
                 // 鍚戜笂绾у钩鍙�
-                if (correlationInfo instanceof ParentPlatform) {
-                    try {
-                        ParentPlatform parentPlatform = (ParentPlatform)correlationInfo;
-                        commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId());
-                    } catch (SipException | InvalidArgumentException | ParseException e) {
-                        logger.error("[鍛戒护鍙戦�佸け璐 鍥芥爣绾ц仈 鍙戦�丅YE: {}", e.getMessage());
-                    }
+                try {
+                    commanderForPlatform.streamByeCmd(platform, callIdHeader.getCallId());
+                } catch (SipException | InvalidArgumentException | ParseException e) {
+                    logger.error("[鍛戒护鍙戦�佸け璐 鍥芥爣绾ц仈 鍙戦�丅YE: {}", e.getMessage());
                 }
             }
+
         }
     }
 
     @Override
-    public void talkCmd(Device device, String channelId, MediaServerItem mediaServerItem, String stream, AudioBroadcastEvent event) {
+    public void talkCmd(Device device, String channelId, MediaServer mediaServerItem, String stream, AudioBroadcastEvent event) {
         if (device == null || channelId == null) {
             return;
         }
@@ -1458,8 +1491,8 @@
             SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
             if (sendRtpItem != null && sendRtpItem.isOnlyAudio()) {
                 // 鏌ヨ娴佹槸鍚﹀瓨鍦紝涓嶅瓨鍦ㄥ垯璁や负鏄紓甯哥姸鎬�
-                MediaServerItem mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
-                Boolean streamReady = zlmServerFactory.isStreamReady(mediaServer, sendRtpItem.getApp(), sendRtpItem.getStream());
+                MediaServer mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+                Boolean streamReady = mediaServerService.isStreamReady(mediaServer, sendRtpItem.getApp(), sendRtpItem.getStream());
                 if (streamReady) {
                     logger.warn("[璇煶瀵硅] 姝e湪璇煶骞挎挱锛屾棤娉曞紑鍚闊抽�氳瘽锛� {}", channelId);
                     event.call("姝e湪璇煶骞挎挱");
@@ -1472,8 +1505,8 @@
 
         SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, stream, null);
         if (sendRtpItem != null) {
-            MediaServerItem mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
-            Boolean streamReady = zlmServerFactory.isStreamReady(mediaServer, "rtp", sendRtpItem.getReceiveStream());
+            MediaServer mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+            Boolean streamReady = mediaServerService.isStreamReady(mediaServer, "rtp", sendRtpItem.getReceiveStream());
             if (streamReady) {
                 logger.warn("[璇煶瀵硅] 杩涜涓細 {}", channelId);
                 event.call("璇煶瀵硅杩涜涓�");
@@ -1483,7 +1516,7 @@
             }
         }
 
-        talk(mediaServerItem, device, channelId, stream, (mediaServerItem1, hookParam) -> {
+        talk(mediaServerItem, device, channelId, stream, (hookData) -> {
             logger.info("[璇煶瀵硅] 鏀跺埌璁惧鍙戞潵鐨勬祦");
         }, eventResult -> {
             logger.warn("[璇煶瀵硅] 澶辫触锛寋}/{}, 閿欒鐮� {} {}", device.getDeviceId(), channelId, eventResult.statusCode, eventResult.msg);
@@ -1517,15 +1550,10 @@
             return;
         }
 
-        MediaServerItem mediaServer = mediaServerService.getOne(mediaServerId);
+        MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
 
         if (streamIsReady == null || streamIsReady) {
-            Map<String, Object> param = new HashMap<>();
-            param.put("vhost", "__defaultVhost__");
-            param.put("app", sendRtpItem.getApp());
-            param.put("stream", sendRtpItem.getStream());
-            param.put("ssrc", sendRtpItem.getSsrc());
-            zlmServerFactory.stopSendRtpStream(mediaServer, param);
+            mediaServerService.stopSendRtp(mediaServer, sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getSsrc());
         }
 
         ssrcFactory.releaseSsrc(mediaServerId, sendRtpItem.getSsrc());
@@ -1552,7 +1580,7 @@
         if (inviteInfo != null) {
             if (inviteInfo.getStreamInfo() != null) {
                 // 宸插瓨鍦ㄧ嚎鐩存帴鎴浘
-                MediaServerItem mediaServerItemInuse = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
+                MediaServer mediaServerItemInuse = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
                 String streamUrl;
                 if (mediaServerItemInuse.getRtspPort() != 0) {
                     streamUrl = String.format("rtsp://127.0.0.1:%s/%s/%s", mediaServerItemInuse.getRtspPort(), "rtp",  inviteInfo.getStreamInfo().getStream());
@@ -1562,7 +1590,7 @@
                 String path = "snap";
                 // 璇锋眰鎴浘
                 logger.info("[璇锋眰鎴浘]: " + fileName);
-                zlmresTfulUtils.getSnap(mediaServerItemInuse, streamUrl, 15, 1, path, fileName);
+                mediaServerService.getSnap(mediaServerItemInuse, streamUrl, 15, 1, path, fileName);
                 File snapFile = new File(path + File.separator + fileName);
                 if (snapFile.exists()) {
                     errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapFile.getAbsoluteFile());
@@ -1573,7 +1601,7 @@
             }
         }
 
-        MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
+        MediaServer newMediaServerItem = getNewMediaServerItem(device);
         play(newMediaServerItem, deviceId, channelId, null, (code, msg, data)->{
             if (code == InviteErrorCode.SUCCESS.getCode()) {
                 InviteInfo inviteInfoForPlay = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
index f0230f7..6692aa8 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
@@ -1,6 +1,5 @@
 package com.genersoft.iot.vmp.service.impl;
 
-import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.genersoft.iot.vmp.common.GeneralCallback;
@@ -9,17 +8,19 @@
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
-import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
+import com.genersoft.iot.vmp.media.event.hook.Hook;
+import com.genersoft.iot.vmp.media.event.hook.HookType;
+import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
+import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent;
+import com.genersoft.iot.vmp.media.event.media.MediaNotFoundEvent;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
 import com.genersoft.iot.vmp.service.IGbStreamService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
-import com.genersoft.iot.vmp.service.IMediaService;
 import com.genersoft.iot.vmp.service.IStreamProxyService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
@@ -29,11 +30,14 @@
 import com.genersoft.iot.vmp.utils.DateUtil;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
 import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
+import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 import com.github.pagehelper.PageInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.TransactionDefinition;
@@ -59,12 +63,6 @@
 
     @Autowired
     private IVideoManagerStorage videoManagerStorager;
-
-    @Autowired
-    private IMediaService mediaService;
-
-    @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
 
     @Autowired
     private ZLMServerFactory zlmServerFactory;
@@ -94,7 +92,7 @@
     private IMediaServerService mediaServerService;
 
     @Autowired
-    private ZlmHttpHookSubscribe hookSubscribe;
+    private HookSubscribe hookSubscribe;
 
     @Autowired
     private DynamicTask dynamicTask;
@@ -105,31 +103,62 @@
     @Autowired
     TransactionDefinition transactionDefinition;
 
+    /**
+     * 娴佸埌鏉ョ殑澶勭悊
+     */
+    @Async("taskExecutor")
+    @org.springframework.context.event.EventListener
+    public void onApplicationEvent(MediaArrivalEvent event) {
+        if ("rtsp".equals(event.getSchema())) {
+            updateStatus(true, event.getApp(), event.getStream());
+        }
+    }
+
+    /**
+     * 娴佺寮�鐨勫鐞�
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaDepartureEvent event) {
+        if ("rtsp".equals(event.getSchema())) {
+            updateStatus(false, event.getApp(), event.getStream());
+        }
+    }
+
+    /**
+     * 娴佺寮�鐨勫鐞�
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaNotFoundEvent event) {
+        if ("rtp".equals(event.getApp())) {
+            return;
+        }
+        // 鎷夋祦浠g悊
+        StreamProxyItem streamProxyByAppAndStream = getStreamProxyByAppAndStream(event.getApp(), event.getStream());
+        if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) {
+            start(event.getApp(), event.getStream());
+        }
+    }
+
 
     @Override
     public void save(StreamProxyItem param, GeneralCallback<StreamInfo> callback) {
-        MediaServerItem mediaInfo;
+        MediaServer mediaServer;
         if (ObjectUtils.isEmpty(param.getMediaServerId()) || "auto".equals(param.getMediaServerId())){
-            mediaInfo = mediaServerService.getMediaServerForMinimumLoad(null);
+            mediaServer = mediaServerService.getMediaServerForMinimumLoad(null);
         }else {
-            mediaInfo = mediaServerService.getOne(param.getMediaServerId());
+            mediaServer = mediaServerService.getOne(param.getMediaServerId());
         }
-        if (mediaInfo == null) {
+        if (mediaServer == null) {
             logger.warn("淇濆瓨浠g悊鏈壘鍒板湪绾跨殑ZLM...");
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "淇濆瓨浠g悊鏈壘鍒板湪绾跨殑ZLM");
         }
         String dstUrl;
         if ("ffmpeg".equalsIgnoreCase(param.getType())) {
-            JSONObject jsonObject = zlmresTfulUtils.getMediaServerConfig(mediaInfo);
-            if (jsonObject.getInteger("code") != 0) {
-                throw new ControllerException(ErrorCode.ERROR100.getCode(), "鑾峰彇娴佸獟浣撻厤缃け璐�");
-            }
-            JSONArray dataArray = jsonObject.getJSONArray("data");
-            JSONObject mediaServerConfig = dataArray.getJSONObject(0);
-            if (ObjectUtils.isEmpty(param.getFfmpegCmdKey())) {
-                param.setFfmpegCmdKey("ffmpeg.cmd");
-            }
-            String ffmpegCmd = mediaServerConfig.getString(param.getFfmpegCmdKey());
+
+            String ffmpegCmd = mediaServerService.getFfmpegCmd(mediaServer, param.getFfmpegCmdKey());
+
             if (ffmpegCmd == null) {
                 throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpeg鎷夋祦浠g悊鏃犳硶鑾峰彇ffmpeg cmd");
             }
@@ -140,25 +169,25 @@
             int port;
             String schemaForUri;
             if (schema.equalsIgnoreCase("rtsp")) {
-                port = mediaInfo.getRtspPort();
+                port = mediaServer.getRtspPort();
                 schemaForUri = schema;
             }else if (schema.equalsIgnoreCase("flv")) {
-                port = mediaInfo.getRtmpPort();
+                port = mediaServer.getRtmpPort();
                 schemaForUri = schema;
             }else {
-                port = mediaInfo.getRtmpPort();
+                port = mediaServer.getRtmpPort();
                 schemaForUri = schema;
             }
 
             dstUrl = String.format("%s://%s:%s/%s/%s", schemaForUri, "127.0.0.1", port, param.getApp(),
                     param.getStream());
         }else {
-            dstUrl = String.format("rtsp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtspPort(), param.getApp(),
+            dstUrl = String.format("rtsp://%s:%s/%s/%s", "127.0.0.1", mediaServer.getRtspPort(), param.getApp(),
                     param.getStream());
         }
         param.setDstUrl(dstUrl);
         logger.info("[鎷夋祦浠g悊] 杈撳嚭鍦板潃涓猴細{}", dstUrl);
-        param.setMediaServerId(mediaInfo.getId());
+        param.setMediaServerId(mediaServer.getId());
         boolean saveResult;
         // 鏇存柊
         if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) {
@@ -170,17 +199,17 @@
             callback.run(ErrorCode.ERROR100.getCode(), "淇濆瓨澶辫触", null);
             return;
         }
-        HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed(param.getApp(), param.getStream(), true, "rtsp", mediaInfo.getId());
-        hookSubscribe.addSubscribe(hookSubscribeForStreamChange, (mediaServerItem, response) -> {
-            StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(
-                    mediaInfo, param.getApp(), param.getStream(), null, null);
+        Hook hook = Hook.getInstance(HookType.on_media_arrival, param.getApp(), param.getStream(), mediaServer.getId());
+        hookSubscribe.addSubscribe(hook, (hookData) -> {
+            StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(
+                    mediaServer, param.getApp(), param.getStream(), null, null);
             callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
         });
         if (param.isEnable()) {
             String talkKey = UUID.randomUUID().toString();
             String delayTalkKey = UUID.randomUUID().toString();
             dynamicTask.startDelay(delayTalkKey, ()->{
-                StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(param.getApp(), param.getStream(), mediaInfo.getId(), false);
+                StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStreamWithCheck(param.getApp(), param.getStream(), mediaServer.getId(), false);
                 if (streamInfo != null) {
                     callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
                 }else {
@@ -188,12 +217,12 @@
                     callback.run(ErrorCode.ERROR100.getCode(), "瓒呮椂", null);
                 }
             }, 7000);
-            JSONObject jsonObject = addStreamProxyToZlm(param);
-            if (jsonObject != null && jsonObject.getInteger("code") == 0) {
-                hookSubscribe.removeSubscribe(hookSubscribeForStreamChange);
+            WVPResult<String> result = addStreamProxyToZlm(param);
+            if (result != null && result.getCode() == 0) {
+                hookSubscribe.removeSubscribe(hook);
                 dynamicTask.stop(talkKey);
-                StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(
-                        mediaInfo, param.getApp(), param.getStream(), null, null);
+                StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(
+                        mediaServer, param.getApp(), param.getStream(), null, null);
                 callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
             }else {
                 param.setEnable(false);
@@ -203,16 +232,16 @@
                 }else {
                     updateStreamProxy(param);
                 }
-                if (jsonObject == null){
+                if (result == null){
                     callback.run(ErrorCode.ERROR100.getCode(), "璁板綍宸蹭繚瀛橈紝鍚敤澶辫触", null);
                 }else {
-                    callback.run(ErrorCode.ERROR100.getCode(), jsonObject.getString("msg"), null);
+                    callback.run(ErrorCode.ERROR100.getCode(), result.getMsg(), null);
                 }
             }
         }
         else{
-            StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(
-                    mediaInfo, param.getApp(), param.getStream(), null, null);
+            StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(
+                    mediaServer, param.getApp(), param.getStream(), null, null);
             callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
         }
     }
@@ -308,38 +337,34 @@
     }
 
     @Override
-    public JSONObject addStreamProxyToZlm(StreamProxyItem param) {
-        JSONObject result = null;
-        MediaServerItem mediaServerItem = null;
+    public WVPResult<String> addStreamProxyToZlm(StreamProxyItem param) {
+        WVPResult<String> result = null;
+        MediaServer mediaServer = null;
         if (param.getMediaServerId() == null) {
             logger.warn("娣诲姞浠g悊鏃禡ediaServerId 涓簄ull");
             return null;
         }else {
-            mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
+            mediaServer = mediaServerService.getOne(param.getMediaServerId());
         }
-        if (mediaServerItem == null) {
+        if (mediaServer == null) {
             return null;
         }
-        if (zlmServerFactory.isStreamReady(mediaServerItem, param.getApp(), param.getStream())) {
-            zlmresTfulUtils.closeStreams(mediaServerItem, param.getApp(), param.getStream());
+        if (mediaServerService.isStreamReady(mediaServer, param.getApp(), param.getStream())) {
+            mediaServerService.closeStreams(mediaServer, param.getApp(), param.getStream());
         }
+        String msgResult;
         if ("ffmpeg".equalsIgnoreCase(param.getType())){
-            result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrcUrl().trim(), param.getDstUrl(),
-                    param.getTimeoutMs() + "", param.isEnableAudio(), param.isEnableMp4(),
+            result = mediaServerService.addFFmpegSource(mediaServer, param.getSrcUrl().trim(), param.getDstUrl(),
+                    param.getTimeoutMs(), param.isEnableAudio(), param.isEnableMp4(),
                     param.getFfmpegCmdKey());
         }else {
-            result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl().trim(),
+            result = mediaServerService.addStreamProxy(mediaServer, param.getApp(), param.getStream(), param.getUrl().trim(),
                     param.isEnableAudio(), param.isEnableMp4(), param.getRtpType());
         }
-        if (result != null && result.getInteger("code") == 0) {
-            JSONObject data = result.getJSONObject("data");
-            if (data == null) {
-                logger.warn("[鑾峰彇鎷夋祦浠g悊鐨勭粨鏋滄暟鎹瓺ata] 澶辫触锛� {}", result );
-                return result;
-            }
-            String key = data.getString("key");
+        if (result != null && result.getCode() == 0) {
+            String key = result.getData();
             if (key == null) {
-                logger.warn("[鑾峰彇鎷夋祦浠g悊鐨勭粨鏋滄暟鎹瓺ata涓殑KEY] 澶辫触锛� {}", result );
+                logger.warn("[鑾峰彇鎷夋祦浠g悊鐨勭粨鏋滄暟鎹瓺ata] 澶辫触锛� {}", result );
                 return result;
             }
             param.setStreamKey(key);
@@ -349,16 +374,23 @@
     }
 
     @Override
-    public JSONObject removeStreamProxyFromZlm(StreamProxyItem param) {
+    public Boolean removeStreamProxyFromZlm(StreamProxyItem param) {
         if (param ==null) {
             return null;
         }
-        MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
-        JSONObject result = null;
+        MediaServer mediaServer = mediaServerService.getOne(param.getMediaServerId());
+        if (mediaServer == null) {
+            return null;
+        }
+        List<StreamInfo> mediaList = mediaServerService.getMediaList(mediaServer, param.getApp(), param.getStream(), null);
+        if (mediaList == null || mediaList.isEmpty()) {
+            return true;
+        }
+        Boolean result = false;
         if ("ffmpeg".equalsIgnoreCase(param.getType())){
-            result = zlmresTfulUtils.delFFmpegSource(mediaServerItem, param.getStreamKey());
+            result = mediaServerService.delFFmpegSource(mediaServer, param.getStreamKey());
         }else {
-            result = zlmresTfulUtils.delStreamProxy(mediaServerItem, param.getStreamKey());
+            result = mediaServerService.delStreamProxy(mediaServer, param.getStreamKey());
         }
         return result;
     }
@@ -379,8 +411,8 @@
             gbStreamMapper.del(app, stream);
             videoManagerStorager.deleteStreamProxy(app, stream);
             redisCatchStorage.removeStream(streamProxyItem.getMediaServerId(), "PULL", app, stream);
-            JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem);
-            if (jsonObject != null && jsonObject.getInteger("code") == 0) {
+            Boolean result = removeStreamProxyFromZlm(streamProxyItem);
+            if (result != null && result) {
                 logger.info("[绉婚櫎浠g悊]锛� 浠g悊锛� {}/{}, 浠巣lm绉婚櫎鎴愬姛", app, stream);
             }else {
                 logger.info("[绉婚櫎浠g悊]锛� 浠g悊锛� {}/{}, 浠巣lm绉婚櫎澶辫触", app, stream);
@@ -393,16 +425,16 @@
         boolean result = false;
         StreamProxyItem streamProxy = videoManagerStorager.queryStreamProxy(app, stream);
         if (streamProxy != null && !streamProxy.isEnable() ) {
-            JSONObject jsonObject = addStreamProxyToZlm(streamProxy);
-            if (jsonObject == null) {
+            WVPResult<String> wvpResult = addStreamProxyToZlm(streamProxy);
+            if (wvpResult == null) {
                 return false;
             }
-            if (jsonObject.getInteger("code") == 0) {
+            if (wvpResult.getCode() == 0) {
                 result = true;
                 streamProxy.setEnable(true);
                 updateStreamProxy(streamProxy);
             }else {
-                logger.info("鍚敤浠g悊澶辫触锛� {}/{}->{}({})", app, stream, jsonObject.getString("msg"),
+                logger.info("鍚敤浠g悊澶辫触锛� {}/{}->{}({})", app, stream, wvpResult.getMsg(),
                         streamProxy.getSrcUrl() == null? streamProxy.getUrl():streamProxy.getSrcUrl());
             }
         } else if (streamProxy != null && streamProxy.isEnable()) {
@@ -416,8 +448,8 @@
         boolean result = false;
         StreamProxyItem streamProxyDto = videoManagerStorager.queryStreamProxy(app, stream);
         if (streamProxyDto != null && streamProxyDto.isEnable()) {
-            JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyDto);
-            if (jsonObject != null && jsonObject.getInteger("code") == 0) {
+            Boolean removed = removeStreamProxyFromZlm(streamProxyDto);
+            if (removed != null && removed) {
                 streamProxyDto.setEnable(false);
                 result = updateStreamProxy(streamProxyDto);
             }
@@ -426,20 +458,8 @@
     }
 
     @Override
-    public JSONObject getFFmpegCMDs(MediaServerItem mediaServerItem) {
-        JSONObject result = new JSONObject();
-        JSONObject mediaServerConfigResuly = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
-        if (mediaServerConfigResuly != null && mediaServerConfigResuly.getInteger("code") == 0
-                && mediaServerConfigResuly.getJSONArray("data").size() > 0){
-            JSONObject mediaServerConfig = mediaServerConfigResuly.getJSONArray("data").getJSONObject(0);
-
-            for (String key : mediaServerConfig.keySet()) {
-                if (key.startsWith("ffmpeg.cmd")){
-                    result.put(key, mediaServerConfig.getString(key));
-                }
-            }
-        }
-        return result;
+    public Map<String, String> getFFmpegCMDs(MediaServer mediaServer) {
+        return mediaServerService.getFFmpegCMDs(mediaServer);
     }
 
 
@@ -465,8 +485,8 @@
                 mediaServerId, true);
         for (StreamProxyItem streamProxyDto : streamProxyListForEnable) {
             logger.info("鎭㈠娴佷唬鐞嗭紝" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
-            JSONObject jsonObject = addStreamProxyToZlm(streamProxyDto);
-            if (jsonObject == null) {
+            WVPResult<String> wvpResult = addStreamProxyToZlm(streamProxyDto);
+            if (wvpResult == null) {
                 // 璁剧疆涓虹绾�
                 logger.info("鎭㈠娴佷唬鐞嗗け璐�" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
                 updateStatus(false, streamProxyDto.getApp(), streamProxyDto.getStream());
@@ -516,44 +536,30 @@
     }
 
     private void syncPullStream(String mediaServerId){
-        MediaServerItem mediaServer = mediaServerService.getOne(mediaServerId);
+        MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
         if (mediaServer != null) {
             List<OnStreamChangedHookParam> allPullStream = redisCatchStorage.getStreams(mediaServerId, "PULL");
-            if (allPullStream.size() > 0) {
-                zlmresTfulUtils.getMediaList(mediaServer, jsonObject->{
-                    Map<String, StreamInfo> stringStreamInfoMap = new HashMap<>();
-                    if (jsonObject.getInteger("code") == 0) {
-                        JSONArray data = jsonObject.getJSONArray("data");
-                        if(data != null && data.size() > 0) {
-                            for (int i = 0; i < data.size(); i++) {
-                                JSONObject streamJSONObj = data.getJSONObject(i);
-                                if ("rtsp".equals(streamJSONObj.getString("schema"))) {
-                                    StreamInfo streamInfo = new StreamInfo();
-                                    String app = streamJSONObj.getString("app");
-                                    String stream = streamJSONObj.getString("stream");
-                                    streamInfo.setApp(app);
-                                    streamInfo.setStream(stream);
-                                    stringStreamInfoMap.put(app+stream, streamInfo);
-                                }
-                            }
+            if (!allPullStream.isEmpty()) {
+                List<StreamInfo> mediaList = mediaServerService.getMediaList(mediaServer, null, null, null);
+                Map<String, StreamInfo> stringStreamInfoMap = new HashMap<>();
+                if (mediaList != null && !mediaList.isEmpty()) {
+                    for (StreamInfo streamInfo : mediaList) {
+                        stringStreamInfoMap.put(streamInfo.getApp() + streamInfo.getStream(), streamInfo);
+                    }
+                }
+                if (stringStreamInfoMap.isEmpty()) {
+                    redisCatchStorage.removeStream(mediaServerId, "PULL");
+                }else {
+                    for (String key : stringStreamInfoMap.keySet()) {
+                        StreamInfo streamInfo = stringStreamInfoMap.get(key);
+                        if (stringStreamInfoMap.get(streamInfo.getApp() + streamInfo.getStream()) == null) {
+                            redisCatchStorage.removeStream(mediaServerId, "PULL", streamInfo.getApp(),
+                                    streamInfo.getStream());
                         }
                     }
-                    if (stringStreamInfoMap.size() == 0) {
-                        redisCatchStorage.removeStream(mediaServerId, "PULL");
-                    }else {
-                        for (String key : stringStreamInfoMap.keySet()) {
-                            StreamInfo streamInfo = stringStreamInfoMap.get(key);
-                            if (stringStreamInfoMap.get(streamInfo.getApp() + streamInfo.getStream()) == null) {
-                                redisCatchStorage.removeStream(mediaServerId, "PULL", streamInfo.getApp(),
-                                        streamInfo.getStream());
-                            }
-                        }
-                    }
-                });
+                }
             }
-
         }
-
     }
 
     @Override
@@ -569,13 +575,13 @@
     @Scheduled(cron = "* 0/10 * * * ?")
     public void asyncCheckStreamProxyStatus() {
 
-        List<MediaServerItem> all = mediaServerService.getAllOnline();
+        List<MediaServer> all = mediaServerService.getAllOnline();
 
         if (CollectionUtils.isEmpty(all)){
             return;
         }
 
-        Map<String, MediaServerItem> serverItemMap = all.stream().collect(Collectors.toMap(MediaServerItem::getId, Function.identity(), (m1, m2) -> m1));
+        Map<String, MediaServer> serverItemMap = all.stream().collect(Collectors.toMap(MediaServer::getId, Function.identity(), (m1, m2) -> m1));
 
         List<StreamProxyItem> list = videoManagerStorager.getStreamProxyListForEnable(true);
 
@@ -585,15 +591,14 @@
 
         for (StreamProxyItem streamProxyItem : list) {
 
-            MediaServerItem mediaServerItem = serverItemMap.get(streamProxyItem.getMediaServerId());
+            MediaServer mediaServerItem = serverItemMap.get(streamProxyItem.getMediaServerId());
 
-            // TODO 鏀寔鍏朵粬 schema
-            JSONObject mediaInfo = zlmresTfulUtils.isMediaOnline(mediaServerItem, streamProxyItem.getApp(), streamProxyItem.getStream(), "rtsp");
+            MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServerItem, streamProxyItem.getApp(), streamProxyItem.getStream());
 
             if (mediaInfo == null){
                 streamProxyItem.setStatus(false);
             } else {
-                if (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online")) {
+                if (mediaInfo.getOnline() != null && mediaInfo.getOnline()) {
                     streamProxyItem.setStatus(true);
                 } else {
                     streamProxyItem.setStatus(false);
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
index e2d7e68..652bcdd 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
@@ -1,21 +1,25 @@
 package com.genersoft.iot.vmp.service.impl;
 
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
-import com.alibaba.fastjson2.TypeReference;
 import com.baomidou.dynamic.datasource.annotation.DS;
+import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.MediaConfig;
 import com.genersoft.iot.vmp.conf.UserSetting;
-import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.gb28181.bean.GbStream;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
-import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
-import com.genersoft.iot.vmp.media.zlm.dto.*;
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
+import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
+import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
+import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.OriginType;
 import com.genersoft.iot.vmp.service.IGbStreamService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IStreamPushService;
 import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -27,7 +31,9 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.TransactionDefinition;
 import org.springframework.transaction.TransactionStatus;
@@ -67,9 +73,6 @@
     private EventPublisher eventPublisher;
 
     @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
-
-    @Autowired
     private IRedisCatchStorage redisCatchStorage;
 
     @Autowired
@@ -87,33 +90,125 @@
     @Autowired
     private MediaConfig mediaConfig;
 
-
-    @Override
-    public List<StreamPushItem> handleJSON(String jsonData, MediaServerItem mediaServerItem) {
-        if (jsonData == null) {
-            return null;
+    /**
+     * 娴佸埌鏉ョ殑澶勭悊
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaArrivalEvent event) {
+        MediaInfo mediaInfo = event.getMediaInfo();
+        if (mediaInfo == null) {
+            return;
+        }
+        if (mediaInfo.getOriginType() != OriginType.RTMP_PUSH.ordinal()
+                && mediaInfo.getOriginType() != OriginType.RTSP_PUSH.ordinal()
+                && mediaInfo.getOriginType() != OriginType.RTC_PUSH.ordinal()) {
+            return;
         }
 
+        StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(event.getApp(), event.getStream());
+        if (streamAuthorityInfo == null) {
+            streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(event);
+        } else {
+            streamAuthorityInfo.setOriginType(mediaInfo.getOriginType());
+        }
+        redisCatchStorage.updateStreamAuthorityInfo(event.getApp(), event.getStream(), streamAuthorityInfo);
+        StreamPushItem transform = StreamPushItem.getInstance(event, userSetting.getServerId());
+        transform.setPushIng(true);
+        transform.setUpdateTime(DateUtil.getNow());
+        transform.setPushTime(DateUtil.getNow());
+        transform.setSelf(true);
+        StreamPushItem pushInDb = getPush(event.getApp(), event.getStream());
+        if (pushInDb == null) {
+            transform.setCreateTime(DateUtil.getNow());
+            streamPushMapper.add(transform);
+        }else {
+            streamPushMapper.update(transform);
+            gbStreamMapper.updateMediaServer(event.getApp(), event.getStream(), event.getMediaServer().getId());
+        }
+        // TODO 鐩稿叧鐨勪簨浠惰嚜琛岀鐞嗭紝涓嶉渶瑕佸啓鍏LMMediaListManager
+//        ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(transform.getApp(), transform.getStream());
+//        if ( channelOnlineEventLister != null)  {
+//            try {
+//                channelOnlineEventLister.run(transform.getApp(), transform.getStream(), transform.getServerId());;
+//            } catch (ParseException e) {
+//                logger.error("addPush: ", e);
+//            }
+//            removedChannelOnlineEventLister(transform.getApp(), transform.getStream());
+//        }
+        // 鍐椾綑鏁版嵁锛岃嚜宸辩郴缁熶腑鑷敤
+        redisCatchStorage.addPushListItem(event.getApp(), event.getStream(), event);
+
+        // 鍙戦�佹祦鍙樺寲redis娑堟伅
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("serverId", userSetting.getServerId());
+        jsonObject.put("app", event.getApp());
+        jsonObject.put("stream", event.getStream());
+        jsonObject.put("register", true);
+        jsonObject.put("mediaServerId", event.getMediaServer().getId());
+        redisCatchStorage.sendStreamChangeMsg(OriginType.values()[event.getMediaInfo().getOriginType()].getType(), jsonObject);
+    }
+
+    /**
+     * 娴佺寮�鐨勫鐞�
+     */
+    @Async("taskExecutor")
+    @EventListener
+    public void onApplicationEvent(MediaDepartureEvent event) {
+        // 鍏煎娴佹敞閿�鏃剁被鍨嬩粠redis璁板綍鑾峰彇
+        OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo(
+                event.getApp(), event.getStream(), event.getMediaServer().getId());
+        if (onStreamChangedHookParam != null) {
+            String type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType();
+            redisCatchStorage.removeStream(event.getMediaServer().getId(), type, event.getApp(), event.getStream());
+            if ("PUSH".equalsIgnoreCase(type)) {
+                // 鍐椾綑鏁版嵁锛岃嚜宸辩郴缁熶腑鑷敤
+                redisCatchStorage.removePushListItem(event.getApp(), event.getStream(), event.getMediaServer().getId());
+            }
+            if (type != null) {
+                // 鍙戦�佹祦鍙樺寲redis娑堟伅
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("serverId", userSetting.getServerId());
+                jsonObject.put("app", event.getApp());
+                jsonObject.put("stream", event.getStream());
+                jsonObject.put("register", false);
+                jsonObject.put("mediaServerId", event.getMediaServer().getId());
+                redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
+            }
+        }
+        GbStream gbStream = gbStreamMapper.selectOne(event.getApp(), event.getStream());
+        if (gbStream != null) {
+            if (userSetting.isUsePushingAsStatus()) {
+                streamPushMapper.updatePushStatus(event.getApp(), event.getStream(), false);
+                eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
+            }
+        }else {
+            streamPushMapper.del(event.getApp(), event.getStream());
+        }
+    }
+
+
+    private List<StreamPushItem> handleJSON(List<StreamInfo> streamInfoList) {
+        if (streamInfoList == null || streamInfoList.isEmpty()) {
+            return null;
+        }
         Map<String, StreamPushItem> result = new HashMap<>();
-
-        List<OnStreamChangedHookParam> onStreamChangedHookParams = JSON.parseObject(jsonData, new TypeReference<List<OnStreamChangedHookParam>>() {});
-        for (OnStreamChangedHookParam item : onStreamChangedHookParams) {
-
+        for (StreamInfo streamInfo : streamInfoList) {
             // 涓嶄繚瀛樺浗鏍囨帹鐞嗕互鍙婃媺娴佷唬鐞嗙殑娴�
-            if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal()
-                    || item.getOriginType() == OriginType.RTMP_PUSH.ordinal()
-                    || item.getOriginType() == OriginType.RTC_PUSH.ordinal() ) {
-                String key = item.getApp() + "_" + item.getStream();
+            if (streamInfo.getOriginType() == OriginType.RTSP_PUSH.ordinal()
+                    || streamInfo.getOriginType() == OriginType.RTMP_PUSH.ordinal()
+                    || streamInfo.getOriginType() == OriginType.RTC_PUSH.ordinal() ) {
+                String key = streamInfo.getApp() + "_" + streamInfo.getStream();
                 StreamPushItem streamPushItem = result.get(key);
                 if (streamPushItem == null) {
-                    streamPushItem = transform(item);
+                    streamPushItem = streamPushItem.getInstance(streamInfo);
                     result.put(key, streamPushItem);
                 }
             }
         }
-
         return new ArrayList<>(result.values());
     }
+
     @Override
     public StreamPushItem transform(OnStreamChangedHookParam item) {
         StreamPushItem streamPushItem = new StreamPushItem();
@@ -122,7 +217,7 @@
         streamPushItem.setStream(item.getStream());
         streamPushItem.setAliveSecond(item.getAliveSecond());
         streamPushItem.setOriginSock(item.getOriginSock());
-        streamPushItem.setTotalReaderCount(item.getTotalReaderCount());
+        streamPushItem.setTotalReaderCount(item.getTotalReaderCount() + "");
         streamPushItem.setOriginType(item.getOriginType());
         streamPushItem.setOriginTypeStr(item.getOriginTypeStr());
         streamPushItem.setOriginUrl(item.getOriginUrl());
@@ -164,15 +259,10 @@
         gbStreamService.sendCatalogMsg(stream, CatalogEvent.DEL);
         platformGbStreamMapper.delByAppAndStream(stream.getApp(), stream.getStream());
         int del = gbStreamMapper.del(stream.getApp(), stream.getStream());
-        MediaServerItem mediaInfo = mediaServerService.getOne(stream.getMediaServerId());
-        JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, stream.getApp(), stream.getStream());
-        if (mediaList != null) {
-            if (mediaList.getInteger("code") == 0) {
-                JSONArray data = mediaList.getJSONArray("data");
-                if (data == null) {
-                    streamPushMapper.del(stream.getApp(), stream.getStream());
-                }
-            }
+        MediaServer mediaInfo = mediaServerService.getOne(stream.getMediaServerId());
+        List<StreamInfo> mediaList = mediaServerService.getMediaList(mediaInfo, stream.getApp(), stream.getStream(), null);
+        if (mediaList != null && mediaList.isEmpty()) {
+            streamPushMapper.del(stream.getApp(), stream.getStream());
         }
         return del > 0;
     }
@@ -195,8 +285,8 @@
         gbStreamMapper.del(app, streamId);
         int delStream = streamPushMapper.del(app, streamId);
         if (delStream > 0) {
-            MediaServerItem mediaServerItem = mediaServerService.getOne(streamPushItem.getMediaServerId());
-            zlmresTfulUtils.closeStreams(mediaServerItem,app, streamId);
+            MediaServer mediaServerItem = mediaServerService.getOne(streamPushItem.getMediaServerId());
+            mediaServerService.closeStreams(mediaServerItem,app, streamId);
         }
         return true;
     }
@@ -204,7 +294,7 @@
     @Override
     public void zlmServerOnline(String mediaServerId) {
         // 鍚屾zlm鎺ㄦ祦淇℃伅
-        MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
+        MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId);
         if (mediaServerItem == null) {
             return;
         }
@@ -232,71 +322,61 @@
         for (StreamAuthorityInfo streamAuthorityInfo : allStreamAuthorityInfo) {
             streamAuthorityInfoInfoMap.put(streamAuthorityInfo.getApp() + streamAuthorityInfo.getStream(), streamAuthorityInfo);
         }
-        zlmresTfulUtils.getMediaList(mediaServerItem, (mediaList ->{
-            if (mediaList == null) {
-                return;
+        List<StreamInfo> mediaList = mediaServerService.getMediaList(mediaServerItem, null, null, null);
+        if (mediaList == null) {
+            return;
+        }
+        List<StreamPushItem> streamPushItems = handleJSON(mediaList);
+        if (streamPushItems != null) {
+            for (StreamPushItem streamPushItem : streamPushItems) {
+                pushItemMap.remove(streamPushItem.getApp() + streamPushItem.getStream());
+                streamInfoPushItemMap.remove(streamPushItem.getApp() + streamPushItem.getStream());
+                streamAuthorityInfoInfoMap.remove(streamPushItem.getApp() + streamPushItem.getStream());
             }
-            String dataStr = mediaList.getString("data");
-
-            Integer code = mediaList.getInteger("code");
-            List<StreamPushItem> streamPushItems = null;
-            if (code == 0 ) {
-                if (dataStr != null) {
-                    streamPushItems = handleJSON(dataStr, mediaServerItem);
-                }
-            }
-
-            if (streamPushItems != null) {
-                for (StreamPushItem streamPushItem : streamPushItems) {
-                    pushItemMap.remove(streamPushItem.getApp() + streamPushItem.getStream());
-                    streamInfoPushItemMap.remove(streamPushItem.getApp() + streamPushItem.getStream());
-                    streamAuthorityInfoInfoMap.remove(streamPushItem.getApp() + streamPushItem.getStream());
-                }
-            }
-            List<StreamPushItem> offlinePushItems = new ArrayList<>(pushItemMap.values());
-            if (offlinePushItems.size() > 0) {
-                String type = "PUSH";
-                int runLimit = 300;
-                if (offlinePushItems.size() > runLimit) {
-                    for (int i = 0; i < offlinePushItems.size(); i += runLimit) {
-                        int toIndex = i + runLimit;
-                        if (i + runLimit > offlinePushItems.size()) {
-                            toIndex = offlinePushItems.size();
-                        }
-                        List<StreamPushItem> streamPushItemsSub = offlinePushItems.subList(i, toIndex);
-                        streamPushMapper.delAll(streamPushItemsSub);
+        }
+        List<StreamPushItem> offlinePushItems = new ArrayList<>(pushItemMap.values());
+        if (offlinePushItems.size() > 0) {
+            String type = "PUSH";
+            int runLimit = 300;
+            if (offlinePushItems.size() > runLimit) {
+                for (int i = 0; i < offlinePushItems.size(); i += runLimit) {
+                    int toIndex = i + runLimit;
+                    if (i + runLimit > offlinePushItems.size()) {
+                        toIndex = offlinePushItems.size();
                     }
-                }else {
-                    streamPushMapper.delAll(offlinePushItems);
+                    List<StreamPushItem> streamPushItemsSub = offlinePushItems.subList(i, toIndex);
+                    streamPushMapper.delAll(streamPushItemsSub);
                 }
-
-            }
-            Collection<OnStreamChangedHookParam> offlineOnStreamChangedHookParamList = streamInfoPushItemMap.values();
-            if (offlineOnStreamChangedHookParamList.size() > 0) {
-                String type = "PUSH";
-                for (OnStreamChangedHookParam offlineOnStreamChangedHookParam : offlineOnStreamChangedHookParamList) {
-                    JSONObject jsonObject = new JSONObject();
-                    jsonObject.put("serverId", userSetting.getServerId());
-                    jsonObject.put("app", offlineOnStreamChangedHookParam.getApp());
-                    jsonObject.put("stream", offlineOnStreamChangedHookParam.getStream());
-                    jsonObject.put("register", false);
-                    jsonObject.put("mediaServerId", mediaServerId);
-                    redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
-                    // 绉婚櫎redis鍐呮祦鐨勪俊鎭�
-                    redisCatchStorage.removeStream(mediaServerItem.getId(), "PUSH", offlineOnStreamChangedHookParam.getApp(), offlineOnStreamChangedHookParam.getStream());
-                    // 鍐椾綑鏁版嵁锛岃嚜宸辩郴缁熶腑鑷敤
-                    redisCatchStorage.removePushListItem(offlineOnStreamChangedHookParam.getApp(), offlineOnStreamChangedHookParam.getStream(), mediaServerItem.getId());
-                }
+            }else {
+                streamPushMapper.delAll(offlinePushItems);
             }
 
-            Collection<StreamAuthorityInfo> streamAuthorityInfos = streamAuthorityInfoInfoMap.values();
-            if (streamAuthorityInfos.size() > 0) {
-                for (StreamAuthorityInfo streamAuthorityInfo : streamAuthorityInfos) {
-                    // 绉婚櫎redis鍐呮祦鐨勪俊鎭�
-                    redisCatchStorage.removeStreamAuthorityInfo(streamAuthorityInfo.getApp(), streamAuthorityInfo.getStream());
-                }
+        }
+        Collection<OnStreamChangedHookParam> offlineOnStreamChangedHookParamList = streamInfoPushItemMap.values();
+        if (offlineOnStreamChangedHookParamList.size() > 0) {
+            String type = "PUSH";
+            for (OnStreamChangedHookParam offlineOnStreamChangedHookParam : offlineOnStreamChangedHookParamList) {
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("serverId", userSetting.getServerId());
+                jsonObject.put("app", offlineOnStreamChangedHookParam.getApp());
+                jsonObject.put("stream", offlineOnStreamChangedHookParam.getStream());
+                jsonObject.put("register", false);
+                jsonObject.put("mediaServerId", mediaServerId);
+                redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
+                // 绉婚櫎redis鍐呮祦鐨勪俊鎭�
+                redisCatchStorage.removeStream(mediaServerItem.getId(), "PUSH", offlineOnStreamChangedHookParam.getApp(), offlineOnStreamChangedHookParam.getStream());
+                // 鍐椾綑鏁版嵁锛岃嚜宸辩郴缁熶腑鑷敤
+                redisCatchStorage.removePushListItem(offlineOnStreamChangedHookParam.getApp(), offlineOnStreamChangedHookParam.getStream(), mediaServerItem.getId());
             }
-        }));
+        }
+
+        Collection<StreamAuthorityInfo> streamAuthorityInfos = streamAuthorityInfoInfoMap.values();
+        if (streamAuthorityInfos.size() > 0) {
+            for (StreamAuthorityInfo streamAuthorityInfo : streamAuthorityInfos) {
+                // 绉婚櫎redis鍐呮祦鐨勪俊鎭�
+                redisCatchStorage.removeStreamAuthorityInfo(streamAuthorityInfo.getApp(), streamAuthorityInfo.getStream());
+            }
+        }
     }
 
     @Override
@@ -470,8 +550,8 @@
         int delStream = streamPushMapper.delAllForGbStream(gbStreams);
         if (delStream > 0) {
             for (GbStream gbStream : gbStreams) {
-                MediaServerItem mediaServerItem = mediaServerService.getOne(gbStream.getMediaServerId());
-                zlmresTfulUtils.closeStreams(mediaServerItem, gbStream.getApp(), gbStream.getStream());
+                MediaServer mediaServerItem = mediaServerService.getOne(gbStream.getMediaServerId());
+                mediaServerService.closeStreams(mediaServerItem, gbStream.getApp(), gbStream.getStream());
             }
 
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
index 3b990f0..14287e0 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
@@ -6,12 +6,12 @@
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
+import com.genersoft.iot.vmp.media.event.hook.Hook;
+import com.genersoft.iot.vmp.media.event.hook.HookType;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.bean.*;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
@@ -61,9 +61,9 @@
      */
     public static final  int ERROR_CODE_TIMEOUT = -3;
 
-    private Map<String, PlayMsgCallback> callbacks = new ConcurrentHashMap<>();
-    private Map<String, PlayMsgCallbackForStartSendRtpStream> callbacksForStartSendRtpStream = new ConcurrentHashMap<>();
-    private Map<String, PlayMsgErrorCallback> callbacksForError = new ConcurrentHashMap<>();
+    private final Map<String, PlayMsgCallback> callbacks = new ConcurrentHashMap<>();
+    private final Map<String, PlayMsgCallbackForStartSendRtpStream> callbacksForStartSendRtpStream = new ConcurrentHashMap<>();
+    private final Map<String, PlayMsgErrorCallback> callbacksForError = new ConcurrentHashMap<>();
 
     @Autowired
     private UserSetting userSetting;
@@ -87,9 +87,9 @@
 
 
     @Autowired
-    private ZlmHttpHookSubscribe subscribe;
+    private HookSubscribe subscribe;
 
-    private ConcurrentLinkedQueue<Message> taskQueue = new ConcurrentLinkedQueue<>();
+    private final ConcurrentLinkedQueue<Message> taskQueue = new ConcurrentLinkedQueue<>();
 
     @Qualifier("taskExecutor")
     @Autowired
@@ -219,7 +219,7 @@
      * 澶勭悊鏀跺埌鐨勮姹傛帹娴佺殑璇锋眰
      */
     private void requestPushStreamMsgHand(RequestPushStreamMsg requestPushStreamMsg, String fromId, String serial) {
-        MediaServerItem mediaInfo = mediaServerService.getOne(requestPushStreamMsg.getMediaServerId());
+        MediaServer mediaInfo = mediaServerService.getOne(requestPushStreamMsg.getMediaServerId());
         if (mediaInfo == null) {
             // TODO 鍥炲閿欒
             return;
@@ -258,7 +258,7 @@
      * 澶勭悊鏀跺埌鐨勮姹俿endItem鐨勮姹�
      */
     private void requestSendItemMsgHand(RequestSendItemMsg content, String toId, String serial) {
-        MediaServerItem mediaServerItem = mediaServerService.getOne(content.getMediaServerId());
+        MediaServer mediaServerItem = mediaServerService.getOne(content.getMediaServerId());
         if (mediaServerItem == null) {
             logger.info("[鍥炲鎺ㄦ祦淇℃伅] 娴佸獟浣搟}涓嶅瓨鍦� ", content.getMediaServerId());
 
@@ -274,7 +274,7 @@
             return;
         }
         // 纭畾娴佹槸鍚﹀湪绾�
-        Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, content.getApp(), content.getStream());
+        Boolean streamReady = mediaServerService.isStreamReady(mediaServerItem, content.getApp(), content.getStream());
         if (streamReady != null && streamReady) {
             logger.info("[鍥炲鎺ㄦ祦淇℃伅]  {}/{}", content.getApp(), content.getStream());
             responseSendItem(mediaServerItem, content, toId, serial);
@@ -297,9 +297,8 @@
             }, userSetting.getPlatformPlayTimeout());
 
             // 娣诲姞璁㈤槄
-            HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(content.getApp(), content.getStream(), true, "rtsp", mediaServerItem.getId());
-
-            subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam)->{
+            Hook hook = Hook.getInstance(HookType.on_media_arrival, content.getApp(), content.getStream(), content.getMediaServerId());
+            subscribe.addSubscribe(hook, (hookData)->{
                         dynamicTask.stop(taskKey);
                         responseSendItem(mediaServerItem, content, toId, serial);
                     });
@@ -317,7 +316,7 @@
     /**
      * 灏嗚幏鍙栧埌鐨剆endItem鍙戦�佸嚭鍘�
      */
-    private void responseSendItem(MediaServerItem mediaServerItem, RequestSendItemMsg content, String toId, String serial) {
+    private void responseSendItem(MediaServer mediaServerItem, RequestSendItemMsg content, String toId, String serial) {
         SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, content.getIp(),
                 content.getPort(), content.getSsrc(), content.getPlatformId(),
                 content.getApp(), content.getStream(), content.getChannelId(),
@@ -449,7 +448,7 @@
             logger.info("[REDIS 鎵ц鍏朵粬骞冲彴鐨勮姹傚仠姝㈡帹娴乚 澶辫触锛� sendRtpItem涓篘ULL");
             return;
         }
-        MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+        MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
         if (mediaInfo == null) {
             // TODO 鍥炲閿欒
             return;
diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java
index a031573..e7cba6b 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java
@@ -2,12 +2,14 @@
 
 import com.alibaba.fastjson2.JSON;
 import com.genersoft.iot.vmp.conf.UserSetting;
+import com.genersoft.iot.vmp.gb28181.bean.InviteStreamType;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
-import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IStreamPushService;
 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
 import com.genersoft.iot.vmp.service.bean.MessageForPushChannelResponse;
@@ -23,6 +25,7 @@
 import javax.sip.InvalidArgumentException;
 import javax.sip.SipException;
 import java.text.ParseException;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -83,6 +86,26 @@
                             logger.error("[鍛戒护鍙戦�佸け璐 鍥芥爣绾ц仈 鍙戦�丅YE: {}", e.getMessage());
                         }
                     }
+                    if (push.isSelf()) {
+                        // 鍋滄鍚戜笂绾ф帹娴�
+                        String streamId = sendRtpItem.getStream();
+                        Map<String, Object> param = new HashMap<>();
+                        param.put("vhost","__defaultVhost__");
+                        param.put("app",sendRtpItem.getApp());
+                        param.put("stream",streamId);
+                        param.put("ssrc",sendRtpItem.getSsrc());
+                        logger.info("[REDIS娑堟伅-鎺ㄦ祦缁撴潫] 鍋滄鍚戜笂绾ф帹娴侊細{}", streamId);
+                        MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+                        redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), sendRtpItem.getCallId(), sendRtpItem.getStream());
+                        zlmServerFactory.stopSendRtpStream(mediaInfo, param);
+                        if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) {
+                            MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
+                                    sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(),
+                                    sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId());
+                            messageForPushChannel.setPlatFormIndex(parentPlatform.getId());
+                            redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel);
+                        }
+                    }
                 }
             }
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java
index dc342b0..49ffd75 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java
@@ -5,7 +5,7 @@
 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.genersoft.iot.vmp.service.IGbStreamService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IStreamPushService;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import org.slf4j.Logger;
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 66db103..c483db6 100755
--- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -6,8 +6,10 @@
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
+import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
@@ -89,7 +91,7 @@
      * @param app
      * @param streamId
      */
-    void addStream(MediaServerItem mediaServerItem, String type, String app, String streamId, OnStreamChangedHookParam item);
+    void addStream(MediaServer mediaServerItem, String type, String app, String streamId, OnStreamChangedHookParam item);
 
     /**
      * 绉婚櫎娴佷俊鎭粠redis
@@ -209,9 +211,9 @@
 
     void sendPlatformStopPlayMsg(MessageForPushChannel messageForPushChannel);
 
-    void addPushListItem(String app, String stream, OnStreamChangedHookParam param);
+    void addPushListItem(String app, String stream, MediaArrivalEvent param);
 
-    OnStreamChangedHookParam getPushListItem(String app, String stream);
+    StreamPushItem getPushListItem(String app, String stream);
 
     void removePushListItem(String app, String stream, String mediaServerId);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java
index 08f67ba..22f2ce0 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java
@@ -1,6 +1,6 @@
 package com.genersoft.iot.vmp.storager.dao;
 
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
 import org.apache.ibatis.annotations.*;
 
@@ -55,7 +55,7 @@
             " </script>")
     List<CloudRecordItem> getList(@Param("query") String query, @Param("app") String app, @Param("stream") String stream,
                                   @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp,
-                                  @Param("callId")String callId, List<MediaServerItem> mediaServerItemList);
+                                  @Param("callId")String callId, List<MediaServer> mediaServerItemList);
 
 
     @Select(" <script>" +
@@ -73,7 +73,7 @@
             " </script>")
     List<String> queryRecordFilePathList(@Param("app") String app, @Param("stream") String stream,
                                   @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp,
-                                  @Param("callId")String callId, List<MediaServerItem> mediaServerItemList);
+                                  @Param("callId")String callId, List<MediaServer> mediaServerItemList);
 
     @Update(" <script>" +
             "update wvp_cloud_record set collect = #{collect} where file_path in " +
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
index 4678591..d34657f 100755
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
@@ -1,6 +1,6 @@
 package com.genersoft.iot.vmp.storager.dao;
 
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import org.apache.ibatis.annotations.*;
 import org.apache.ibatis.annotations.Param;
 import org.springframework.stereotype.Repository;
@@ -24,6 +24,10 @@
             "rtmp_ssl_port,"+
             "rtp_proxy_port,"+
             "rtsp_port,"+
+            "flv_port," +
+            "flv_ssl_port," +
+            "ws_flv_port," +
+            "ws_flv_ssl_port," +
             "rtsp_ssl_port,"+
             "auto_config,"+
             "secret,"+
@@ -34,6 +38,7 @@
             "record_day,"+
             "record_path,"+
             "default_server,"+
+            "type,"+
             "create_time,"+
             "update_time,"+
             "hook_alive_interval"+
@@ -50,6 +55,10 @@
             "#{rtmpSSlPort}, " +
             "#{rtpProxyPort}, " +
             "#{rtspPort}, " +
+            "#{flvPort}, " +
+            "#{flvSSLPort}, " +
+            "#{wsFlvPort}, " +
+            "#{wsFlvSSLPort}, " +
             "#{rtspSSLPort}, " +
             "#{autoConfig}, " +
             "#{secret}, " +
@@ -60,10 +69,11 @@
             "#{recordDay}, " +
             "#{recordPath}, " +
             "#{defaultServer}, " +
+            "#{type}, " +
             "#{createTime}, " +
             "#{updateTime}, " +
             "#{hookAliveInterval})")
-    int add(MediaServerItem mediaServerItem);
+    int add(MediaServer mediaServerItem);
 
     @Update(value = {" <script>" +
             "UPDATE wvp_media_server " +
@@ -79,6 +89,10 @@
             "<if test=\"rtpProxyPort != null\">, rtp_proxy_port=#{rtpProxyPort}</if>" +
             "<if test=\"rtspPort != null\">, rtsp_port=#{rtspPort}</if>" +
             "<if test=\"rtspSSLPort != null\">, rtsp_ssl_port=#{rtspSSLPort}</if>" +
+            "<if test=\"flvPort != null\">, flv_port=#{flvPort}</if>" +
+            "<if test=\"flvSSLPort != null\">, flv_ssl_port=#{flvSSLPort}</if>" +
+            "<if test=\"wsFlvPort != null\">, ws_flv_port=#{wsFlvPort}</if>" +
+            "<if test=\"wsFlvSSLPort != null\">, ws_flv_ssl_port=#{wsFlvSSLPort}</if>" +
             "<if test=\"autoConfig != null\">, auto_config=#{autoConfig}</if>" +
             "<if test=\"rtpEnable != null\">, rtp_enable=#{rtpEnable}</if>" +
             "<if test=\"rtpPortRange != null\">, rtp_port_range=#{rtpPortRange}</if>" +
@@ -88,9 +102,10 @@
             "<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" +
             "<if test=\"recordDay != null\">, record_day=#{recordDay}</if>" +
             "<if test=\"recordPath != null\">, record_path=#{recordPath}</if>" +
+            "<if test=\"type != null\">, type=#{type}</if>" +
             "WHERE id=#{id}"+
             " </script>"})
-    int update(MediaServerItem mediaServerItem);
+    int update(MediaServer mediaServerItem);
 
     @Update(value = {" <script>" +
             "UPDATE wvp_media_server " +
@@ -105,6 +120,10 @@
             "<if test=\"rtpProxyPort != null\">, rtp_proxy_port=#{rtpProxyPort}</if>" +
             "<if test=\"rtspPort != null\">, rtsp_port=#{rtspPort}</if>" +
             "<if test=\"rtspSSLPort != null\">, rtsp_ssl_port=#{rtspSSLPort}</if>" +
+            "<if test=\"flvPort != null\">, flv_port=#{flvPort}</if>" +
+            "<if test=\"flvSSLPort != null\">, flv_ssl_port=#{flvSSLPort}</if>" +
+            "<if test=\"wsFlvPort != null\">, ws_flv_port=#{wsFlvPort}</if>" +
+            "<if test=\"wsFlvSSLPort != null\">, ws_flv_ssl_port=#{wsFlvSSLPort}</if>" +
             "<if test=\"autoConfig != null\">, auto_config=#{autoConfig}</if>" +
             "<if test=\"rtpEnable != null\">, rtp_enable=#{rtpEnable}</if>" +
             "<if test=\"rtpPortRange != null\">, rtp_port_range=#{rtpPortRange}</if>" +
@@ -113,16 +132,17 @@
             "<if test=\"recordAssistPort != null\">, record_assist_port=#{recordAssistPort}</if>" +
             "<if test=\"recordDay != null\">, record_day=#{recordDay}</if>" +
             "<if test=\"recordPath != null\">, record_path=#{recordPath}</if>" +
+            "<if test=\"type != null\">, type=#{type}</if>" +
             "<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" +
             "WHERE ip=#{ip} and http_port=#{httpPort}"+
             " </script>"})
-    int updateByHostAndPort(MediaServerItem mediaServerItem);
+    int updateByHostAndPort(MediaServer mediaServerItem);
 
     @Select("SELECT * FROM wvp_media_server WHERE id=#{id}")
-    MediaServerItem queryOne(String id);
+    MediaServer queryOne(String id);
 
     @Select("SELECT * FROM wvp_media_server")
-    List<MediaServerItem> queryAll();
+    List<MediaServer> queryAll();
 
     @Delete("DELETE FROM wvp_media_server WHERE id=#{id}")
     void delOne(String id);
@@ -134,12 +154,12 @@
     int delDefault();
 
     @Select("SELECT * FROM wvp_media_server WHERE ip=#{host} and http_port=#{port}")
-    MediaServerItem queryOneByHostAndPort(@Param("host") String host, @Param("port") int port);
+    MediaServer queryOneByHostAndPort(@Param("host") String host, @Param("port") int port);
 
     @Select("SELECT * FROM wvp_media_server WHERE default_server=true")
-    MediaServerItem queryDefault();
+    MediaServer queryDefault();
 
     @Select("SELECT * FROM wvp_media_server WHERE record_assist_port > 0")
-    List<MediaServerItem> queryAllWithAssistPort();
+    List<MediaServer> queryAllWithAssistPort();
 
 }
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 1eac4df..b17b4d7 100755
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -9,8 +9,10 @@
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
+import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
@@ -313,7 +315,7 @@
     }
 
     @Override
-    public void addStream(MediaServerItem mediaServerItem, String type, String app, String streamId, OnStreamChangedHookParam onStreamChangedHookParam) {
+    public void addStream(MediaServer mediaServerItem, String type, String app, String streamId, OnStreamChangedHookParam onStreamChangedHookParam) {
         // 鏌ユ壘鏄惁浣跨敤浜哻allID
         StreamAuthorityInfo streamAuthorityInfo = getStreamAuthorityInfo(app, streamId);
         String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX  + userSetting.getServerId() + "_" + type + "_" + app + "_" + streamId + "_" + mediaServerItem.getId();
@@ -651,21 +653,22 @@
     }
 
     @Override
-    public void addPushListItem(String app, String stream, OnStreamChangedHookParam param) {
+    public void addPushListItem(String app, String stream, MediaArrivalEvent event) {
         String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream;
-        redisTemplate.opsForValue().set(key, param);
+        StreamPushItem streamPushItem = StreamPushItem.getInstance(event, userSetting.getServerId());
+        redisTemplate.opsForValue().set(key, streamPushItem);
     }
 
     @Override
-    public OnStreamChangedHookParam getPushListItem(String app, String stream) {
+    public StreamPushItem getPushListItem(String app, String stream) {
         String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream;
-        return (OnStreamChangedHookParam)redisTemplate.opsForValue().get(key);
+        return (StreamPushItem)redisTemplate.opsForValue().get(key);
     }
 
     @Override
     public void removePushListItem(String app, String stream, String mediaServerId) {
         String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream;
-        OnStreamChangedHookParam param = (OnStreamChangedHookParam)redisTemplate.opsForValue().get(key);
+        StreamPushItem param = (StreamPushItem)redisTemplate.opsForValue().get(key);
         if (param != null && param.getMediaServerId().equalsIgnoreCase(mediaServerId)) {
             redisTemplate.delete(key);
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/CloudRecordUtils.java b/src/main/java/com/genersoft/iot/vmp/utils/CloudRecordUtils.java
index 8954bd7..10cb620 100644
--- a/src/main/java/com/genersoft/iot/vmp/utils/CloudRecordUtils.java
+++ b/src/main/java/com/genersoft/iot/vmp/utils/CloudRecordUtils.java
@@ -1,11 +1,11 @@
 package com.genersoft.iot.vmp.utils;
 
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
 
 public class CloudRecordUtils {
 
-    public static DownloadFileInfo getDownloadFilePath(MediaServerItem mediaServerItem, String filePath) {
+    public static DownloadFileInfo getDownloadFilePath(MediaServer mediaServerItem, String filePath) {
         DownloadFileInfo downloadFileInfo = new DownloadFileInfo();
 
         String pathTemplate = "%s://%s:%s/index/api/downloadFile?file_path=" + filePath;
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java
index 4974209..193c95d 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java
@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.vmanager.bean;
 
 import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
 import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
 import io.swagger.v3.oas.annotations.media.Schema;
 
@@ -86,7 +87,7 @@
     private String mediaServerId;
 
     @Schema(description = "娴佺紪鐮佷俊鎭�")
-    private Object tracks;
+    private MediaInfo mediaInfo;
 
     @Schema(description = "寮�濮嬫椂闂�")
     private String startTime;
@@ -170,7 +171,7 @@
         }
 
         this.mediaServerId = streamInfo.getMediaServerId();
-        this.tracks = streamInfo.getTracks();
+        this.mediaInfo = streamInfo.getMediaInfo();
         this.startTime = streamInfo.getStartTime();
         this.endTime = streamInfo.getEndTime();
         this.progress = streamInfo.getProgress();
@@ -388,12 +389,12 @@
         this.mediaServerId = mediaServerId;
     }
 
-    public Object getTracks() {
-        return tracks;
+    public MediaInfo getMediaInfo() {
+        return mediaInfo;
     }
 
-    public void setTracks(Object tracks) {
-        this.tracks = tracks;
+    public void setMediaInfo(MediaInfo mediaInfo) {
+        this.mediaInfo = mediaInfo;
     }
 
     public String getStartTime() {
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java
index b37a3d9..da8bbc8 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java
@@ -3,9 +3,9 @@
 import com.alibaba.fastjson2.JSONArray;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.conf.security.JwtUtils;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.ICloudRecordService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
 import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
@@ -67,16 +67,16 @@
         if (ObjectUtils.isEmpty(month)) {
             month = calendar.get(Calendar.MONTH) + 1;
         }
-        List<MediaServerItem> mediaServerItems;
+        List<MediaServer> mediaServerItems;
         if (!ObjectUtils.isEmpty(mediaServerId)) {
             mediaServerItems = new ArrayList<>();
-            MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
+            MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId);
             if (mediaServerItem == null) {
                 throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒版祦濯掍綋: " + mediaServerId);
             }
             mediaServerItems.add(mediaServerItem);
         } else {
-            mediaServerItems = mediaServerService.getAll();
+            mediaServerItems = mediaServerService.getAllOnlineList();
         }
         if (mediaServerItems.isEmpty()) {
             return new ArrayList<>();
@@ -110,16 +110,16 @@
         logger.info("[浜戠褰曞儚] 鏌ヨ app->{}, stream->{}, mediaServerId->{}, page->{}, count->{}, startTime->{}, endTime->{}",
                 app, stream, mediaServerId, page, count, startTime, endTime);
 
-        List<MediaServerItem> mediaServerItems;
+        List<MediaServer> mediaServerItems;
         if (!ObjectUtils.isEmpty(mediaServerId)) {
             mediaServerItems = new ArrayList<>();
-            MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
+            MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId);
             if (mediaServerItem == null) {
                 throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒版祦濯掍綋: " + mediaServerId);
             }
             mediaServerItems.add(mediaServerItem);
         } else {
-            mediaServerItems = mediaServerService.getAll();
+            mediaServerItems = mediaServerService.getAllOnlineList();
         }
         if (mediaServerItems.isEmpty()) {
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "褰撳墠鏃犳祦濯掍綋");
@@ -162,7 +162,7 @@
             @RequestParam(required = false) String callId,
             @RequestParam(required = false) String remoteHost
     ){
-        MediaServerItem mediaServerItem;
+        MediaServer mediaServerItem;
         if (mediaServerId == null) {
             mediaServerItem = mediaServerService.getDefaultMediaServer();
         }else {
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
index 56d192e..26e9685 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
@@ -5,6 +5,7 @@
 import com.genersoft.iot.vmp.conf.security.JwtUtils;
 import com.genersoft.iot.vmp.conf.security.SecurityUtils;
 import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
 import com.genersoft.iot.vmp.service.IMediaService;
 import com.genersoft.iot.vmp.service.IStreamProxyService;
@@ -36,9 +37,10 @@
     private IRedisCatchStorage redisCatchStorage;
 
     @Autowired
-    private IMediaService mediaService;
-    @Autowired
     private IStreamProxyService streamProxyService;
+
+    @Autowired
+    private IMediaServerService mediaServerService;
 
 
     /**
@@ -85,9 +87,9 @@
             String host = request.getHeader("Host");
             String localAddr = host.split(":")[0];
             logger.info("浣跨敤{}浣滀负杩斿洖娴佺殑ip", localAddr);
-            streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, localAddr, authority);
+            streamInfo = mediaServerService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, localAddr, authority);
         }else {
-            streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
+            streamInfo = mediaServerService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
         }
 
         if (streamInfo != null){
@@ -105,9 +107,9 @@
                 String host = request.getHeader("Host");
                 String localAddr = host.split(":")[0];
                 logger.info("浣跨敤{}浣滀负杩斿洖娴佺殑ip", localAddr);
-                streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, localAddr, authority);
+                streamInfo = mediaServerService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, localAddr, authority);
             }else {
-                streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
+                streamInfo = mediaServerService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
             }
             if (streamInfo != null){
                 return new StreamContent(streamInfo);
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
index 97a5baa..1ed3197 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -2,7 +2,6 @@
 
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.common.InviteInfo;
 import com.genersoft.iot.vmp.common.InviteSessionType;
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.UserSetting;
@@ -14,14 +13,11 @@
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
-import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IInviteStreamService;
-import com.genersoft.iot.vmp.service.IMediaServerService;
-import com.genersoft.iot.vmp.service.IMediaService;
 import com.genersoft.iot.vmp.service.IPlayService;
 import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
-import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
@@ -66,22 +62,13 @@
 	private IVideoManagerStorage storager;
 
 	@Autowired
-	private IRedisCatchStorage redisCatchStorage;
-
-	@Autowired
 	private IInviteStreamService inviteStreamService;
-
-	@Autowired
-	private ZLMRESTfulUtils zlmresTfulUtils;
 
 	@Autowired
 	private DeferredResultHolder resultHolder;
 
 	@Autowired
 	private IPlayService playService;
-
-	@Autowired
-	private IMediaService mediaService;
 
 	@Autowired
 	private IMediaServerService mediaServerService;
@@ -99,7 +86,7 @@
 		logger.info("[寮�濮嬬偣鎾璢 deviceId锛歿}, channelId锛歿}, ", deviceId, channelId);
 		// 鑾峰彇鍙敤鐨剒lm
 		Device device = storager.queryVideoDevice(deviceId);
-		MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
+		MediaServer newMediaServerItem = playService.getNewMediaServerItem(device);
 
 		RequestMessage requestMessage = new RequestMessage();
 		String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
@@ -181,50 +168,6 @@
 		json.put("channelId", channelId);
 		return json;
 	}
-
-	/**
-	 * 灏嗕笉鏄痟264鐨勮棰戦�氳繃ffmpeg 杞爜涓篽264 + aac
-	 * @param streamId 娴両D
-	 */
-	@Operation(summary = "灏嗕笉鏄痟264鐨勮棰戦�氳繃ffmpeg 杞爜涓篽264 + aac", security = @SecurityRequirement(name = JwtUtils.HEADER))
-	@Parameter(name = "streamId", description = "瑙嗛娴両D", required = true)
-	@PostMapping("/convert/{streamId}")
-	public JSONObject playConvert(@PathVariable String streamId) {
-//		StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
-
-		InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, streamId);
-		if (inviteInfo == null || inviteInfo.getStreamInfo() == null) {
-			logger.warn("瑙嗛杞爜API璋冪敤澶辫触锛�, 瑙嗛娴佸凡缁忓仠姝�!");
-			throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒拌棰戞祦淇℃伅, 瑙嗛娴佸彲鑳藉凡缁忓仠姝�");
-		}
-		MediaServerItem mediaInfo = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
-		JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
-		if (!rtpInfo.getBoolean("exist")) {
-			logger.warn("瑙嗛杞爜API璋冪敤澶辫触锛�, 瑙嗛娴佸凡鍋滄鎺ㄦ祦!");
-			throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒拌棰戞祦淇℃伅, 瑙嗛娴佸彲鑳藉凡鍋滄鎺ㄦ祦");
-		} else {
-			String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(),
-					streamId );
-			String srcUrl = String.format("rtsp://%s:%s/rtp/%s", "127.0.0.1", mediaInfo.getRtspPort(), streamId);
-			JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(mediaInfo, srcUrl, dstUrl, "1000000", true, false, null);
-			logger.info(jsonObject.toJSONString());
-			if (jsonObject != null && jsonObject.getInteger("code") == 0) {
-				JSONObject data = jsonObject.getJSONObject("data");
-				if (data != null) {
-					JSONObject result = new JSONObject();
-					result.put("key", data.getString("key"));
-					StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStreamWithCheck("convert", streamId, mediaInfo.getId(), false);
-					result.put("StreamInfo", streamInfoResult);
-					return result;
-				}else {
-					throw new ControllerException(ErrorCode.ERROR100.getCode(), "杞爜澶辫触");
-				}
-			}else {
-				throw new ControllerException(ErrorCode.ERROR100.getCode(), "杞爜澶辫触");
-			}
-		}
-	}
-
 	/**
 	 * 缁撴潫杞爜
 	 */
@@ -236,18 +179,12 @@
 		if (mediaServerId == null) {
 			throw new ControllerException(ErrorCode.ERROR400.getCode(), "娴佸獟浣擄細" + mediaServerId + "涓嶅瓨鍦�" );
 		}
-		MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
+		MediaServer mediaInfo = mediaServerService.getOne(mediaServerId);
 		if (mediaInfo == null) {
 			throw new ControllerException(ErrorCode.ERROR100.getCode(), "浣跨敤鐨勬祦濯掍綋宸茬粡鍋滄杩愯" );
 		}else {
-			JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(mediaInfo, key);
-			logger.info(jsonObject.toJSONString());
-			if (jsonObject != null && jsonObject.getInteger("code") == 0) {
-				JSONObject data = jsonObject.getJSONObject("data");
-				if (data == null || data.getBoolean("flag") == null || !data.getBoolean("flag")) {
-					throw new ControllerException(ErrorCode.ERROR100 );
-				}
-			}else {
+			Boolean deleted = mediaServerService.delFFmpegSource(mediaInfo, key);
+			if (!deleted) {
 				throw new ControllerException(ErrorCode.ERROR100 );
 			}
 		}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java
index dbbc7b0..6401a8c 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java
@@ -6,15 +6,13 @@
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.conf.security.JwtUtils;
+import com.genersoft.iot.vmp.media.event.hook.Hook;
+import com.genersoft.iot.vmp.media.event.hook.HookType;
 import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRtpServerTimeoutHookParam;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
 import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
@@ -50,7 +48,7 @@
     private ZLMServerFactory zlmServerFactory;
 
     @Autowired
-    private ZlmHttpHookSubscribe hookSubscribe;
+    private HookSubscribe hookSubscribe;
 
     @Autowired
     private IMediaServerService mediaServerService;
@@ -83,7 +81,7 @@
         logger.info("[绗笁鏂筆S鏈嶅姟瀵规帴->寮�鍚敹娴佸拰鑾峰彇鍙戞祦淇℃伅] isSend->{}, ssrc->{}, callId->{}, stream->{}, tcpMode->{}, callBack->{}",
                 isSend, ssrc, callId, stream, tcpMode==0?"UDP":"TCP琚姩", callBack);
 
-        MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
+        MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
         if (mediaServerItem == null) {
             throw new ControllerException(ErrorCode.ERROR100.getCode(),"娌℃湁鍙敤鐨凪ediaServer");
         }
@@ -108,12 +106,11 @@
         }
         // 娉ㄥ唽鍥炶皟濡傛灉rtp鏀舵祦瓒呮椂鍒欓�氳繃鍥炶皟鍙戦�侀�氱煡
         if (callBack != null) {
-            HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(stream, String.valueOf(ssrcInt), mediaServerItem.getId());
+            Hook hook = Hook.getInstance(HookType.on_rtp_server_timeout, "rtp", stream, mediaServerItem.getId());
             // 璁㈤槄 zlm鍚姩浜嬩欢, 鏂扮殑zlm涔熶細浠庤繖閲岃繘鍏ョ郴缁�
-            hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout,
-                    (mediaServerItemInUse, hookParam)->{
-                        OnRtpServerTimeoutHookParam serverTimeoutHookParam = (OnRtpServerTimeoutHookParam) hookParam;
-                        if (stream.equals(serverTimeoutHookParam.getStream_id())) {
+            hookSubscribe.addSubscribe(hook,
+                    (hookData)->{
+                        if (stream.equals(hookData.getStream())) {
                             logger.info("[绗笁鏂筆S鏈嶅姟瀵规帴->寮�鍚敹娴佸拰鑾峰彇鍙戞祦淇℃伅] 绛夊緟鏀舵祦瓒呮椂 callId->{}, 鍙戦�佸洖璋�", callId);
                             // 灏嗕俊鎭啓鍏edis涓紝浠ュ鍚庣敤
                             redisTemplate.delete(receiveKey);
@@ -126,7 +123,7 @@
                             } catch (IOException e) {
                                 logger.error("[绗笁鏂筆S鏈嶅姟瀵规帴->寮�鍚敹娴佸拰鑾峰彇鍙戞祦淇℃伅] 绛夊緟鏀舵祦瓒呮椂 callId->{}, 鍙戦�佸洖璋冨け璐�", callId, e);
                             }
-                            hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
+                            hookSubscribe.removeSubscribe(hook);
                         }
                     });
         }
@@ -158,7 +155,7 @@
     @Parameter(name = "stream", description = "娴佺殑ID", required = true)
     public void closeRtpServer(String stream) {
         logger.info("[绗笁鏂筆S鏈嶅姟瀵规帴->鍏抽棴鏀舵祦] stream->{}", stream);
-        MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
+        MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
         zlmServerFactory.closeRtpServer(mediaServerItem,stream);
         String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_*_"  + stream;
         List<Object> scan = RedisUtil.scan(redisTemplate, receiveKey);
@@ -201,7 +198,7 @@
                         app,
                         stream,
                         callId);
-        MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
+        MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
         String key = VideoManagerConstants.WVP_OTHER_SEND_PS_INFO + userSetting.getServerId() + "_"  + callId;
         OtherPsSendInfo sendInfo = (OtherPsSendInfo)redisTemplate.opsForValue().get(key);
         if (sendInfo == null) {
@@ -227,7 +224,7 @@
         param.put("src_port", sendInfo.getSendLocalPort());
 
 
-        Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, app, stream);
+        Boolean streamReady = mediaServerService.isStreamReady(mediaServerItem, app, stream);
         if (streamReady) {
             JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, param);
             if (jsonObject.getInteger("code") == 0) {
@@ -241,18 +238,18 @@
         }else {
             logger.info("[绗笁鏂筆S鏈嶅姟瀵规帴->鍙戦�佹祦] 娴佷笉瀛樺湪锛岀瓑寰呮祦涓婄嚎锛宑allId->{}", callId);
             String uuid = UUID.randomUUID().toString();
-            HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed(app, stream, true, "rtsp", mediaServerItem.getId());
+            Hook hook = Hook.getInstance(HookType.on_media_arrival, app, stream, mediaServerItem.getId());
             dynamicTask.startDelay(uuid, ()->{
                 logger.info("[绗笁鏂筆S鏈嶅姟瀵规帴->鍙戦�佹祦] 绛夊緟娴佷笂绾胯秴鏃� callId->{}", callId);
                 redisTemplate.delete(key);
-                hookSubscribe.removeSubscribe(hookSubscribeForStreamChange);
+                hookSubscribe.removeSubscribe(hook);
             }, 10000);
 
             // 璁㈤槄 zlm鍚姩浜嬩欢, 鏂扮殑zlm涔熶細浠庤繖閲岃繘鍏ョ郴缁�
             OtherPsSendInfo finalSendInfo = sendInfo;
-            hookSubscribe.removeSubscribe(hookSubscribeForStreamChange);
-            hookSubscribe.addSubscribe(hookSubscribeForStreamChange,
-                    (mediaServerItemInUse, response)->{
+            hookSubscribe.removeSubscribe(hook);
+            hookSubscribe.addSubscribe(hook,
+                    (hookData)->{
                         dynamicTask.stop(uuid);
                         logger.info("[绗笁鏂筆S鏈嶅姟瀵规帴->鍙戦�佹祦] 娴佷笂绾匡紝寮�濮嬪彂娴� callId->{}", callId);
                         try {
@@ -269,7 +266,7 @@
                             logger.info("[绗笁鏂筆S鏈嶅姟瀵规帴->鍙戦�佹祦] 瑙嗛娴佸彂娴佸け璐ワ紝callId->{}, {}", callId, jsonObject.getString("msg"));
                             throw new ControllerException(ErrorCode.ERROR100.getCode(), "[瑙嗛娴佸彂娴佸け璐 " + jsonObject.getString("msg"));
                         }
-                        hookSubscribe.removeSubscribe(hookSubscribeForStreamChange);
+                        hookSubscribe.removeSubscribe(hook);
                     });
         }
     }
@@ -290,7 +287,7 @@
         param.put("app",sendInfo.getPushApp());
         param.put("stream",sendInfo.getPushStream());
         param.put("ssrc",sendInfo.getPushSSRC());
-        MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
+        MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
         Boolean result = zlmServerFactory.stopSendRtpStream(mediaServerItem, param);
         if (!result) {
             logger.info("[绗笁鏂筆S鏈嶅姟瀵规帴->鍏抽棴鍙戦�佹祦] 澶辫触 callId->{}", callId);
@@ -305,7 +302,7 @@
     @GetMapping(value = "/getTestPort")
     @ResponseBody
     public int getTestPort() {
-        MediaServerItem defaultMediaServer = mediaServerService.getDefaultMediaServer();
+        MediaServer defaultMediaServer = mediaServerService.getDefaultMediaServer();
 
 //        for (int i = 0; i <300; i++) {
 //            new Thread(() -> {
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java
index 5bd4b9d..f42d153 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java
@@ -6,15 +6,13 @@
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.conf.security.JwtUtils;
+import com.genersoft.iot.vmp.media.event.hook.Hook;
+import com.genersoft.iot.vmp.media.event.hook.HookType;
 import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
-import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRtpServerTimeoutHookParam;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
 import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
@@ -54,7 +52,7 @@
     private final static Logger logger = LoggerFactory.getLogger(RtpController.class);
 
     @Autowired
-    private ZlmHttpHookSubscribe hookSubscribe;
+    private HookSubscribe hookSubscribe;
 
     @Autowired
     private IMediaServerService mediaServerService;
@@ -83,7 +81,7 @@
         logger.info("[绗笁鏂规湇鍔″鎺�->寮�鍚敹娴佸拰鑾峰彇鍙戞祦淇℃伅] isSend->{}, ssrc->{}, callId->{}, stream->{}, tcpMode->{}, callBack->{}",
                 isSend, ssrc, callId, stream, tcpMode==0?"UDP":"TCP琚姩", callBack);
 
-        MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
+        MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
         if (mediaServerItem == null) {
             throw new ControllerException(ErrorCode.ERROR100.getCode(),"娌℃湁鍙敤鐨凪ediaServer");
         }
@@ -109,12 +107,11 @@
         }
         // 娉ㄥ唽鍥炶皟濡傛灉rtp鏀舵祦瓒呮椂鍒欓�氳繃鍥炶皟鍙戦�侀�氱煡
         if (callBack != null) {
-            HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(stream, String.valueOf(ssrcInt), mediaServerItem.getId());
+            Hook hook = Hook.getInstance(HookType.on_rtp_server_timeout, "rtp", stream, mediaServerItem.getId());
             // 璁㈤槄 zlm鍚姩浜嬩欢, 鏂扮殑zlm涔熶細浠庤繖閲岃繘鍏ョ郴缁�
-            hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout,
-                    (mediaServerItemInUse, hookParam)->{
-                        OnRtpServerTimeoutHookParam serverTimeoutHookParam = (OnRtpServerTimeoutHookParam) hookParam;
-                        if (stream.equals(serverTimeoutHookParam.getStream_id())) {
+            hookSubscribe.addSubscribe(hook,
+                    (hookData)->{
+                        if (stream.equals(hookData.getStream())) {
                             logger.info("[寮�鍚敹娴佸拰鑾峰彇鍙戞祦淇℃伅] 绛夊緟鏀舵祦瓒呮椂 callId->{}, 鍙戦�佸洖璋�", callId);
                             OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
                             OkHttpClient client = httpClientBuilder.build();
@@ -125,7 +122,7 @@
                             } catch (IOException e) {
                                 logger.error("[绗笁鏂规湇鍔″鎺�->寮�鍚敹娴佸拰鑾峰彇鍙戞祦淇℃伅] 绛夊緟鏀舵祦瓒呮椂 callId->{}, 鍙戦�佸洖璋冨け璐�", callId, e);
                             }
-                            hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
+                            hookSubscribe.removeSubscribe(hook);
                         }
                     });
         }
@@ -162,7 +159,7 @@
     @Parameter(name = "stream", description = "娴佺殑ID", required = true)
     public void closeRtpServer(String stream) {
         logger.info("[绗笁鏂规湇鍔″鎺�->鍏抽棴鏀舵祦] stream->{}", stream);
-        MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
+        MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
         zlmServerFactory.closeRtpServer(mediaServerItem,stream);
         zlmServerFactory.closeRtpServer(mediaServerItem,stream + "_a");
         String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_*_"  + stream;
@@ -225,7 +222,7 @@
         if (!((dstPortForAudio > 0 && !ObjectUtils.isEmpty(dstPortForAudio) || (dstPortForVideo > 0 && !ObjectUtils.isEmpty(dstIpForVideo))))) {
             throw new ControllerException(ErrorCode.ERROR400.getCode(), "鑷冲皯搴旇瀛樺湪涓�缁勯煶棰戞垨瑙嗛鍙戦�佸弬鏁�");
         }
-        MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
+        MediaServer mediaServer = mediaServerService.getDefaultMediaServer();
         String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + "_"  + callId;
         OtherRtpSendInfo sendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(key);
         if (sendInfo == null) {
@@ -278,10 +275,10 @@
             paramForVideo = null;
         }
 
-        Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, app, stream);
+        Boolean streamReady = mediaServerService.isStreamReady(mediaServer, app, stream);
         if (streamReady) {
             if (paramForVideo != null) {
-                JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, paramForVideo);
+                JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServer, paramForVideo);
                 if (jsonObject.getInteger("code") == 0) {
                     logger.info("[绗笁鏂规湇鍔″鎺�->鍙戦�佹祦] 瑙嗛娴佸彂娴佹垚鍔燂紝callId->{}锛宲aram->{}", callId, paramForVideo);
                     redisTemplate.opsForValue().set(key, sendInfo);
@@ -292,7 +289,7 @@
                 }
             }
             if(paramForAudio != null) {
-                JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, paramForAudio);
+                JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServer, paramForAudio);
                 if (jsonObject.getInteger("code") == 0) {
                     logger.info("[绗笁鏂规湇鍔″鎺�->鍙戦�佹祦] 闊抽娴佸彂娴佹垚鍔燂紝callId->{}锛宲aram->{}", callId, paramForAudio);
                     redisTemplate.opsForValue().set(key, sendInfo);
@@ -305,18 +302,18 @@
         }else {
             logger.info("[绗笁鏂规湇鍔″鎺�->鍙戦�佹祦] 娴佷笉瀛樺湪锛岀瓑寰呮祦涓婄嚎锛宑allId->{}", callId);
             String uuid = UUID.randomUUID().toString();
-            HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed(app, stream, true, "rtsp", mediaServerItem.getId());
+            Hook hook = Hook.getInstance(HookType.on_media_arrival, app, stream, mediaServer.getId());
             dynamicTask.startDelay(uuid, ()->{
                 logger.info("[绗笁鏂规湇鍔″鎺�->鍙戦�佹祦] 绛夊緟娴佷笂绾胯秴鏃� callId->{}", callId);
                 redisTemplate.delete(key);
-                hookSubscribe.removeSubscribe(hookSubscribeForStreamChange);
+                hookSubscribe.removeSubscribe(hook);
             }, 10000);
 
             // 璁㈤槄 zlm鍚姩浜嬩欢, 鏂扮殑zlm涔熶細浠庤繖閲岃繘鍏ョ郴缁�
             OtherRtpSendInfo finalSendInfo = sendInfo;
-            hookSubscribe.removeSubscribe(hookSubscribeForStreamChange);
-            hookSubscribe.addSubscribe(hookSubscribeForStreamChange,
-                    (mediaServerItemInUse, response)->{
+            hookSubscribe.removeSubscribe(hook);
+            hookSubscribe.addSubscribe(hook,
+                    (hookData)->{
                         dynamicTask.stop(uuid);
                         logger.info("[绗笁鏂规湇鍔″鎺�->鍙戦�佹祦] 娴佷笂绾匡紝寮�濮嬪彂娴� callId->{}", callId);
                         try {
@@ -325,7 +322,7 @@
                             throw new RuntimeException(e);
                         }
                         if (paramForVideo != null) {
-                            JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, paramForVideo);
+                            JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServer, paramForVideo);
                             if (jsonObject.getInteger("code") == 0) {
                                 logger.info("[绗笁鏂规湇鍔″鎺�->鍙戦�佹祦] 瑙嗛娴佸彂娴佹垚鍔燂紝callId->{}锛宲aram->{}", callId, paramForVideo);
                                 redisTemplate.opsForValue().set(key, finalSendInfo);
@@ -336,7 +333,7 @@
                             }
                         }
                         if(paramForAudio != null) {
-                            JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, paramForAudio);
+                            JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServer, paramForAudio);
                             if (jsonObject.getInteger("code") == 0) {
                                 logger.info("[绗笁鏂规湇鍔″鎺�->鍙戦�佹祦] 闊抽娴佸彂娴佹垚鍔燂紝callId->{}锛宲aram->{}", callId, paramForAudio);
                                 redisTemplate.opsForValue().set(key, finalSendInfo);
@@ -346,7 +343,7 @@
                                 throw new ControllerException(ErrorCode.ERROR100.getCode(), "[闊抽娴佸彂娴佸け璐 " + jsonObject.getString("msg"));
                             }
                         }
-                        hookSubscribe.removeSubscribe(hookSubscribeForStreamChange);
+                        hookSubscribe.removeSubscribe(hook);
                     });
         }
     }
@@ -367,7 +364,7 @@
         param.put("app",sendInfo.getPushApp());
         param.put("stream",sendInfo.getPushStream());
         param.put("ssrc",sendInfo.getPushSSRC());
-        MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
+        MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
         Boolean result = zlmServerFactory.stopSendRtpStream(mediaServerItem, param);
         if (!result) {
             logger.info("[绗笁鏂规湇鍔″鎺�->鍏抽棴鍙戦�佹祦] 澶辫触 callId->{}", callId);
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
index d1c72fc..a7d6041 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
@@ -9,10 +9,8 @@
 import com.genersoft.iot.vmp.conf.VersionInfo;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.conf.security.JwtUtils;
-import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
-import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.*;
 import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -39,8 +37,6 @@
 @RequestMapping("/api/server")
 public class ServerController {
 
-    @Autowired
-    private ZlmHttpHookSubscribe zlmHttpHookSubscribe;
 
     @Autowired
     private IMediaServerService mediaServerService;
@@ -75,21 +71,19 @@
     @Autowired
     private IRedisCatchStorage redisCatchStorage;
 
-    @Autowired
-    private SendRtpPortManager sendRtpPortManager;
 
 
     @GetMapping(value = "/media_server/list")
     @ResponseBody
     @Operation(summary = "娴佸獟浣撴湇鍔″垪琛�", security = @SecurityRequirement(name = JwtUtils.HEADER))
-    public List<MediaServerItem> getMediaServerList() {
+    public List<MediaServer> getMediaServerList() {
         return mediaServerService.getAll();
     }
 
     @GetMapping(value = "/media_server/online/list")
     @ResponseBody
     @Operation(summary = "鍦ㄧ嚎娴佸獟浣撴湇鍔″垪琛�", security = @SecurityRequirement(name = JwtUtils.HEADER))
-    public List<MediaServerItem> getOnlineMediaServerList() {
+    public List<MediaServer> getOnlineMediaServerList() {
         return mediaServerService.getAllOnline();
     }
 
@@ -97,7 +91,7 @@
     @ResponseBody
     @Operation(summary = "鍋滄瑙嗛鍥炴斁", security = @SecurityRequirement(name = JwtUtils.HEADER))
     @Parameter(name = "id", description = "娴佸獟浣撴湇鍔D", required = true)
-    public MediaServerItem getMediaServer(@PathVariable String id) {
+    public MediaServer getMediaServer(@PathVariable String id) {
         return mediaServerService.getOne(id);
     }
 
@@ -107,8 +101,8 @@
     @Parameter(name = "secret", description = "娴佸獟浣撴湇鍔ecret", required = true)
     @GetMapping(value = "/media_server/check")
     @ResponseBody
-    public MediaServerItem checkMediaServer(@RequestParam String ip, @RequestParam int port, @RequestParam String secret) {
-        return mediaServerService.checkMediaServer(ip, port, secret);
+    public MediaServer checkMediaServer(@RequestParam String ip, @RequestParam int port, @RequestParam String secret, @RequestParam String type) {
+        return mediaServerService.checkMediaServer(ip, port, secret, type);
     }
 
     @Operation(summary = "娴嬭瘯娴佸獟浣撳綍鍍忕鐞嗘湇鍔�", security = @SecurityRequirement(name = JwtUtils.HEADER))
@@ -127,8 +121,8 @@
     @Parameter(name = "mediaServerItem", description = "娴佸獟浣撲俊鎭�", required = true)
     @PostMapping(value = "/media_server/save")
     @ResponseBody
-    public void saveMediaServer(@RequestBody MediaServerItem mediaServerItem) {
-        MediaServerItem mediaServerItemInDatabase = mediaServerService.getOne(mediaServerItem.getId());
+    public void saveMediaServer(@RequestBody MediaServer mediaServerItem) {
+        MediaServer mediaServerItemInDatabase = mediaServerService.getOneFromDatabase(mediaServerItem.getId());
 
         if (mediaServerItemInDatabase != null) {
             mediaServerService.update(mediaServerItem);
@@ -142,11 +136,7 @@
     @DeleteMapping(value = "/media_server/delete")
     @ResponseBody
     public void deleteMediaServer(@RequestParam String id) {
-        if (mediaServerService.getOne(id) == null) {
-            throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒版鑺傜偣");
-        }
         mediaServerService.delete(id);
-        mediaServerService.deleteDb(id);
     }
 
 
@@ -220,13 +210,6 @@
         return jsonObject;
     }
 
-    @GetMapping(value = "/hooks")
-    @ResponseBody
-    @Operation(summary = "鑾峰彇褰撳墠鎵�鏈塰ook")
-    public List<IHookSubscribe> getHooks() {
-        return zlmHttpHookSubscribe.getAll();
-    }
-
     @GetMapping(value = "/system/info")
     @ResponseBody
     @Operation(summary = "鑾峰彇绯荤粺淇℃伅")
@@ -241,11 +224,11 @@
     @Operation(summary = "鑾峰彇璐熻浇淇℃伅")
     public List<MediaServerLoad> getMediaLoad() {
         List<MediaServerLoad> result = new ArrayList<>();
-        List<MediaServerItem> allOnline = mediaServerService.getAllOnline();
+        List<MediaServer> allOnline = mediaServerService.getAllOnline();
         if (allOnline.size() == 0) {
             return result;
         }else {
-            for (MediaServerItem mediaServerItem : allOnline) {
+            for (MediaServer mediaServerItem : allOnline) {
                 result.add(mediaServerService.getLoad(mediaServerItem));
             }
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
index 9565000..dd5e703 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
@@ -7,9 +7,9 @@
 import com.genersoft.iot.vmp.conf.security.JwtUtils;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IStreamProxyService;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
@@ -27,6 +27,7 @@
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
 
+import java.util.Map;
 import java.util.UUID;
 
 @SuppressWarnings("rawtypes")
@@ -135,10 +136,10 @@
     @ResponseBody
     @Operation(summary = "鑾峰彇ffmpeg.cmd妯℃澘", security = @SecurityRequirement(name = JwtUtils.HEADER))
     @Parameter(name = "mediaServerId", description = "娴佸獟浣揑D", required = true)
-    public JSONObject getFFmpegCMDs(@RequestParam String mediaServerId){
+    public Map<String, String> getFFmpegCMDs(@RequestParam String mediaServerId){
         logger.debug("鑾峰彇鑺傜偣[ {} ]ffmpeg.cmd妯℃澘", mediaServerId );
 
-        MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
+        MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId);
         if (mediaServerItem == null) {
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "娴佸獟浣擄細 " + mediaServerId + "鏈壘鍒�");
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
index 8202bf5..309cd69 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
@@ -13,7 +13,7 @@
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
-import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IMediaService;
 import com.genersoft.iot.vmp.service.IStreamPushService;
 import com.genersoft.iot.vmp.service.impl.StreamPushUploadFileHandler;
@@ -249,7 +249,7 @@
         if (push != null && !push.isSelf()) {
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏉ヨ嚜鍏朵粬骞冲彴鐨勬帹娴佷俊鎭�");
         }
-        StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
+        StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
         if (streamInfo == null){
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "鑾峰彇鎾斁鍦板潃澶辫触");
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
index 63d9f31..be740c1 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
@@ -9,7 +9,7 @@
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
-import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.service.IDeviceService;
 import com.genersoft.iot.vmp.service.IInviteStreamService;
 import com.genersoft.iot.vmp.service.IPlayService;
@@ -114,7 +114,7 @@
             result.setResult(resultJSON);
             return result;
         }
-        MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
+        MediaServer newMediaServerItem = playService.getNewMediaServerItem(device);
 
         playService.play(newMediaServerItem, serial, code, null, (errorCode, msg, data) -> {
             if (errorCode == InviteErrorCode.SUCCESS.getCode()) {
diff --git a/web_src/src/components/MediaServerManger.vue b/web_src/src/components/MediaServerManger.vue
index 1d3c057..4d6b6bf 100755
--- a/web_src/src/components/MediaServerManger.vue
+++ b/web_src/src/components/MediaServerManger.vue
@@ -10,7 +10,8 @@
     <el-row :gutter="12">
       <el-col :span="num" v-for="item in mediaServerList" :key="item.id">
         <el-card shadow="hover" :body-style="{ padding: '0px'}" class="server-card">
-          <div class="card-img-zlm"></div>
+          <div v-if="item.type === 'zlm'" class="card-img-zlm"></div>
+          <div v-if="item.type === 'abl'" class="card-img-abl"></div>
           <div style="padding: 14px;text-align: left">
             <span style="font-size: 16px">{{item.id}}</span>
             <el-button v-if="!item.defaultServer" icon="el-icon-edit" style="padding: 0;float: right;" type="text" @click="edit(item)">缂栬緫</el-button>
@@ -154,6 +155,13 @@
     background-size: contain;
     margin: 0 auto;
   }
+  .card-img-abl{
+    width: 200px; height: 200px;
+    background: url('~@static/images/abl-logo.jpg') no-repeat center;
+    background-position: center;
+    background-size: contain;
+    margin: 0 auto;
+  }
   .server-card-status-online{
     position: absolute;
     right: 20px;
diff --git a/web_src/src/components/dialog/MediaServerEdit.vue b/web_src/src/components/dialog/MediaServerEdit.vue
index 9808a1c..9d8491e 100755
--- a/web_src/src/components/dialog/MediaServerEdit.vue
+++ b/web_src/src/components/dialog/MediaServerEdit.vue
@@ -20,6 +20,12 @@
           <el-form-item label="SECRET" prop="secret">
             <el-input v-model="mediaServerForm.secret" placeholder="濯掍綋鏈嶅姟SECRET"  clearable :disabled="mediaServerForm.defaultServer"></el-input>
           </el-form-item>
+          <el-form-item label="绫诲瀷" prop="type">
+            <el-select v-model="mediaServerForm.type" style="float: left; width: 100%" >
+              <el-option key="zlm" label="ZLMediaKit" value="zlm"></el-option>
+              <el-option key="abl" label="ABLMediaServer" value="abl"></el-option>
+            </el-select>
+          </el-form-item>
           <el-form-item>
             <div style="float: right;">
               <el-button type="primary" v-if="currentStep === 1 && serverCheck === 1" @click="next" >涓嬩竴姝�</el-button>
@@ -170,7 +176,7 @@
         hookIp: "",
         sdpIp: "",
         streamIp: "",
-        secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc",
+        secret: "",
         httpPort: "",
         httpSSlPort: "",
         recordAssistPort: "",
@@ -182,6 +188,7 @@
         rtpProxyPort: "",
         rtspPort: "",
         rtspSSLPort: "",
+        type: "zlm",
       },
       rtpPortRange1:30000,
       rtpPortRange2:30500,
@@ -330,7 +337,7 @@
         hookIp: "",
         sdpIp: "",
         streamIp: "",
-        secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc",
+        secret: "",
         httpPort: "",
         httpSSlPort: "",
         recordAssistPort: "",
diff --git a/web_src/src/components/service/MediaServer.js b/web_src/src/components/service/MediaServer.js
index d4446f0..b049537 100755
--- a/web_src/src/components/service/MediaServer.js
+++ b/web_src/src/components/service/MediaServer.js
@@ -45,7 +45,8 @@
       params: {
         ip: param.ip,
         port: param.httpPort,
-        secret: param.secret
+        secret: param.secret,
+        type: param.type
       }
     }).then(function (res) {
       if (typeof (callback) == "function") callback(res.data)
diff --git a/web_src/static/images/abl-logo.jpg b/web_src/static/images/abl-logo.jpg
new file mode 100644
index 0000000..82a564d
--- /dev/null
+++ b/web_src/static/images/abl-logo.jpg
Binary files differ
diff --git "a/\346\225\260\346\215\256\345\272\223/\345\210\235\345\247\213\345\214\226-mysql.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-mysql-2.7.0.sql"
similarity index 97%
rename from "\346\225\260\346\215\256\345\272\223/\345\210\235\345\247\213\345\214\226-mysql.sql"
rename to "\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-mysql-2.7.0.sql"
index f3247c1..cf614d9 100644
--- "a/\346\225\260\346\215\256\345\272\223/\345\210\235\345\247\213\345\214\226-mysql.sql"
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-mysql-2.7.0.sql"
@@ -155,8 +155,13 @@
                                   rtp_proxy_port integer,
                                   rtsp_port integer,
                                   rtsp_ssl_port integer,
+                                  flv_port integer,
+                                  flv_ssl_port integer,
+                                  ws_flv_port integer,
+                                  ws_flv_ssl_port integer,
                                   auto_config bool default false,
                                   secret character varying(50),
+                                  type character varying(50) default 'zlm',
                                   rtp_enable bool default false,
                                   rtp_port_range character varying(50),
                                   send_rtp_port_range character varying(50),
@@ -198,6 +203,7 @@
                               update_time character varying(50),
                               as_message_channel bool default false,
                               auto_push_channel bool default false,
+                              send_stream_ip character varying(50),
                               constraint uk_platform_unique_server_gb_id unique (server_gb_id)
 );
 
diff --git "a/\346\225\260\346\215\256\345\272\223/\345\210\235\345\247\213\345\214\226-postgresql-kingbase.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.0.sql"
similarity index 97%
rename from "\346\225\260\346\215\256\345\272\223/\345\210\235\345\247\213\345\214\226-postgresql-kingbase.sql"
rename to "\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.0.sql"
index 17ef270..317e9e0 100644
--- "a/\346\225\260\346\215\256\345\272\223/\345\210\235\345\247\213\345\214\226-postgresql-kingbase.sql"
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.1/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.0.sql"
@@ -155,8 +155,13 @@
                                   rtp_proxy_port integer,
                                   rtsp_port integer,
                                   rtsp_ssl_port integer,
+                                  flv_port integer,
+                                  flv_ssl_port integer,
+                                  ws_flv_port integer,
+                                  ws_flv_ssl_port integer,
                                   auto_config bool default false,
                                   secret character varying(50),
+                                  type character varying(50) default 'zlm',
                                   rtp_enable bool default false,
                                   rtp_port_range character varying(50),
                                   send_rtp_port_range character varying(50),
@@ -198,6 +203,7 @@
                               update_time character varying(50),
                               as_message_channel bool default false,
                               auto_push_channel bool default false,
+                              send_stream_ip character varying(50),
                               constraint uk_platform_unique_server_gb_id unique (server_gb_id)
 );
 
diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-mysql-2.7.0.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-mysql-2.7.0.sql"
new file mode 100644
index 0000000..9a527cb
--- /dev/null
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-mysql-2.7.0.sql"
@@ -0,0 +1,11 @@
+alter table wvp_media_server
+    add  type character varying(50) default 'zlm';
+
+alter table wvp_media_server
+    add flv_port integer;
+alter table wvp_media_server
+    add flv_ssl_port integer;
+alter table wvp_media_server
+    add ws_flv_port integer;
+alter table wvp_media_server
+    add ws_flv_ssl_port integer;
\ No newline at end of file
diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-postgresql-kingbase-2.7.0.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-postgresql-kingbase-2.7.0.sql"
new file mode 100644
index 0000000..9a527cb
--- /dev/null
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.1/\346\233\264\346\226\260-postgresql-kingbase-2.7.0.sql"
@@ -0,0 +1,11 @@
+alter table wvp_media_server
+    add  type character varying(50) default 'zlm';
+
+alter table wvp_media_server
+    add flv_port integer;
+alter table wvp_media_server
+    add flv_ssl_port integer;
+alter table wvp_media_server
+    add ws_flv_port integer;
+alter table wvp_media_server
+    add ws_flv_ssl_port integer;
\ No newline at end of file

--
Gitblit v1.8.0