From 89a9ab4534f10a224f70e546db838423e84a1965 Mon Sep 17 00:00:00 2001
From: 64850858 <648540858@qq.com>
Date: 星期五, 16 七月 2021 16:34:51 +0800
Subject: [PATCH] 添加zlm集群支持

---
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java                             |   13 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java                           |    6 
 web_src/src/components/service/MediaServer.js                                                             |   32 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java                                    |   76 
 src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java                                    |    9 
 src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java                                                |    9 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java                               |   14 
 sql/mysql.sql                                                                                             |   27 
 src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java                                      |   23 
 src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java                                          |    2 
 src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java                              |  340 ++++++
 web_src/src/components/dialog/StreamProxyEdit.vue                                                         |   75 
 src/main/java/com/genersoft/iot/vmp/service/IPlayService.java                                             |   11 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java                                     |   14 
 src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java                                     |   76 +
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java                            |   13 
 web_src/src/components/StreamProxyList.vue                                                                |   15 
 src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java                                      |    4 
 src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java |   25 
 src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java                       |   27 
 src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java                           |   24 
 src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java                                     |   26 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java                               |    7 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java             |   57 
 src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java                                   |   20 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java                             |    7 
 src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java                                          |   91 +
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java                                    |   85 
 src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java                                      |    9 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java            |   10 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaItem.java                                          |   12 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMRunInfo.java                                         |   33 
 src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java                                       |    3 
 src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java                               |   16 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java                     |   15 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java                                              |   13 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java                                         |   13 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java                           |  213 +--
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java                                    |   20 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java                                        |   95 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IMediaServerItem.java                                   |   92 +
 web_src/src/components/PushVideoList.vue                                                                  |    9 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java                |   27 
 src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java                                    |   53 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java                                    |  254 ++++
 web_src/src/components/CloudRecord.vue                                                                    |   36 
 pom.xml                                                                                                   |   10 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java                                   |    4 
 src/main/java/com/genersoft/iot/vmp/web/ApiController.java                                                |    2 
 src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java                              |   25 
 web_src/src/components/dialog/devicePlayer.vue                                                            |   15 
 src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java                                                 |  204 +++
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/SIPRequestAbstractProcessor.java             |    8 
 src/main/java/com/genersoft/iot/vmp/service/IMediaService.java                                            |   37 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java                                              |  196 +-
 src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java                                            |   14 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java                                        |   60 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java                |   17 
 src/main/resources/wvp.sqlite                                                                             |    0 
 src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java                                      |   44 
 src/main/resources/all-application.yml                                                                    |    4 
 src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java                                 |   27 
 src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java                                   |   10 
 src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java                                          |    2 
 /dev/null                                                                                                 |   45 
 src/main/java/com/genersoft/iot/vmp/vmanager/record/RecoderProxyController.java                           |   11 
 src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java                                                 |   39 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java                                    |   92 +
 src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java                                   |   99 +
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java                                            |    9 
 web_src/src/components/control.vue                                                                        |  124 +
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java                             |   74 
 src/main/java/com/genersoft/iot/vmp/web/ApiControlController.java                                         |    2 
 src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java                              |   66 
 74 files changed, 2,431 insertions(+), 860 deletions(-)

diff --git a/pom.xml b/pom.xml
index 074f9fe..6223945 100644
--- a/pom.xml
+++ b/pom.xml
@@ -196,6 +196,16 @@
 			<version>1.12</version>
 		</dependency>
 
+<!--		&lt;!&ndash; 妫�娴嬫枃浠剁紪鐮� &ndash;&gt;-->
+<!--		&lt;!&ndash; https://mvnrepository.com/artifact/cpdetector/cpdetector &ndash;&gt;-->
+<!--		<dependency>-->
+<!--			<groupId>cpdetector</groupId>-->
+<!--			<artifactId>cpdetector</artifactId>-->
+<!--			<version>1.0.8</version>-->
+<!--		</dependency>-->
+
+
+
 		<!-- onvif鍗忚鏍� -->
 		<dependency>
 			<groupId>be.teletask</groupId>
diff --git a/sql/mysql.sql b/sql/mysql.sql
index 21d7a52..0bb4c03 100644
--- a/sql/mysql.sql
+++ b/sql/mysql.sql
@@ -138,6 +138,7 @@
     timeout_ms     int          null,
     ffmpeg_cmd_key varchar(255) null,
     rtp_type       varchar(50) null,
+    mediaServerId       varchar(50) null,
     enable_hls     bit(1)   null,
     enable_mp4     bit(1)   null,
     enable         bit(1)   not null,
@@ -166,4 +167,28 @@
     create_time varchar(50) not null
 );
 
-insert into user (username, password, roleId, create_time) values ('admin', '21232f297a57a5a743894a0e4a801fc3', '0', '2021-04-13 14:14:57');
\ No newline at end of file
+insert into user (username, password, roleId, create_time) values ('admin', '21232f297a57a5a743894a0e4a801fc3', '0', '2021-04-13 14:14:57');
+
+create table media_server (
+      id          varchar(255)
+          primary key,
+      ip varchar(50) NOT NULL,
+      hookIp varchar(50) NOT NULL,
+      sdpIp varchar(50) NOT NULL,
+      streamIp varchar(50) NOT NULL,
+      httpPort int NOT NULL,
+      httpSSlPort int NOT NULL,
+      rtmpPort int NOT NULL,
+      rtmpSSlPort int NOT NULL,
+      rtpProxyPort int NOT NULL,
+      rtspPort int NOT NULL,
+      rtspSSLPort int NOT NULL,
+      autoConfig int NOT NULL,
+      secret varchar(50) NOT NULL,
+      streamNoneReaderDelayMS int NOT NULL,
+      rtpEnable int NOT NULL,
+      rtpPortRange varchar(50) NOT NULL,
+      recordAssistPort int NOT NULL,
+      createTime  varchar(50) not null,
+      updateTime  varchar(50) not null
+);
\ No newline at end of file
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 1336d05..771838d 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -19,6 +19,7 @@
     private String rtmp;
     private String rtsp;
     private String rtc;
+    private String mediaServerId;
     private JSONArray tracks;
 
     public static class TransactionInfo{
@@ -165,4 +166,12 @@
     public void setTransactionInfo(TransactionInfo transactionInfo) {
         this.transactionInfo = transactionInfo;
     }
+
+    public String getMediaServerId() {
+        return mediaServerId;
+    }
+
+    public void setMediaServerId(String mediaServerId) {
+        this.mediaServerId = mediaServerId;
+    }
 }
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 f4e895f..5749314 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -10,33 +10,31 @@
 	
 	public static final String WVP_SERVER_PREFIX = "VMP_wvp_server";
 
-	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_STREAM_PREFIX = "VMP_media_stream";
+	public static final String MEDIA_STREAM_PREFIX = "VMP_MEDIA_STREAM";
 
-	public static final String DEVICE_PREFIX = "VMP_device_";
+	public static final String DEVICE_PREFIX = "VMP_DEVICE_";
 
-	public static final String CACHEKEY_PREFIX = "VMP_channel_";
+	public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_";
 
 	public static final String KEEPLIVEKEY_PREFIX = "VMP_keeplive_";
 
-	public static final String PLAYER_PREFIX = "VMP_player_";
+	public static final String PLAYER_PREFIX = "VMP_PLAYER_";
 
-	public static final String PLAY_BLACK_PREFIX = "VMP_playback_";
+	public static final String PLAY_BLACK_PREFIX = "VMP_PLAYBACK_";
 
-	public static final String PLATFORM_PREFIX = "VMP_platform";
+	public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_PLATFORM_KEEPLIVE_";
 
-	public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_platform_keeplive_";
+	public static final String PLATFORM_CATCH_PREFIX = "VMP_PLATFORM_CATCH_";
 
-	public static final String PLATFORM_CATCH_PREFIX = "VMP_platform_catch_";
+	public static final String PLATFORM_REGISTER_PREFIX = "VMP_PLATFORM_REGISTER_";
 
-	public static final String PLATFORM_REGISTER_PREFIX = "VMP_platform_register_";
+	public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_";
 
-	public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_platform_register_info_";
+	public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_PLATFORM_SEND_RTP_INFO_";
 
-	public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_platform_send_rtp_info_";
-
-	public static final String Pattern_Topic = "VMP_keeplive_platform_";
+	public static final String Pattern_Topic = "VMP_KEEPLIVE_PLATFORM_";
 
 	public static final String EVENT_ONLINE_REGISTER = "1";
 	
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 52292a5..88e8a64 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
@@ -1,11 +1,16 @@
 package com.genersoft.iot.vmp.conf;
 
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.util.StringUtils;
 
 @Configuration("mediaConfig")
-public class MediaConfig {
+public class MediaConfig implements IMediaServerItem {
+
+    @Value("${media.id:}")
+    private String id;
 
     @Value("${media.ip}")
     private String ip;
@@ -25,22 +30,22 @@
     @Value("${media.http-port}")
     private Integer httpPort;
 
-    @Value("${media.http-ssl-port:}")
+    @Value("${media.http-ssl-port:0}")
     private Integer httpSSlPort;
 
-    @Value("${media.rtmp-port:}")
+    @Value("${media.rtmp-port:0}")
     private Integer rtmpPort;
 
-    @Value("${media.rtmp-ssl-port:}")
+    @Value("${media.rtmp-ssl-port:0}")
     private Integer rtmpSSlPort;
 
-    @Value("${media.rtp-proxy-port:}")
+    @Value("${media.rtp-proxy-port:0}")
     private Integer rtpProxyPort;
 
-    @Value("${media.rtsp-port:}")
+    @Value("${media.rtsp-port:0}")
     private Integer rtspPort;
 
-    @Value("${media.rtsp-ssl-port:}")
+    @Value("${media.rtsp-ssl-port:0}")
     private Integer rtspSSLPort;
 
     @Value("${media.auto-config:true}")
@@ -61,6 +66,23 @@
     @Value("${media.record-assist-port:0}")
     private Integer recordAssistPort;
 
+    private String updateTime;
+
+    private String createTime;
+
+    private boolean docker = false;
+
+    private int count;
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+    
     public String getIp() {
         return ip;
     }
@@ -82,80 +104,112 @@
         this.hookIp = hookIp;
     }
 
-    public String getSdpIp() {
-        if (StringUtils.isEmpty(sdpIp)){
-            return ip;
-        }else {
-            return sdpIp;
-        }
+    public String getSipIp() {
+        return sipIp;
+    }
+
+    public void setSipIp(String sipIp) {
+        this.sipIp = sipIp;
     }
 
     public void setSdpIp(String sdpIp) {
         this.sdpIp = sdpIp;
     }
 
-    public String getStreamIp() {
-        if (StringUtils.isEmpty(streamIp)){
-            return ip;
-        }else {
-            return streamIp;
-        }
-    }
-
     public void setStreamIp(String streamIp) {
         this.streamIp = streamIp;
     }
 
-    public Integer getHttpPort() {
+    public int getHttpPort() {
         return httpPort;
+    }
+
+    @Override
+    public void setHttpPort(int httpPort) {
+
     }
 
     public void setHttpPort(Integer httpPort) {
         this.httpPort = httpPort;
     }
 
-    public Integer getHttpSSlPort() {
+    public int getHttpSSlPort() {
         return httpSSlPort;
+    }
+
+    @Override
+    public void setHttpSSlPort(int httpSSlPort) {
+
     }
 
     public void setHttpSSlPort(Integer httpSSlPort) {
         this.httpSSlPort = httpSSlPort;
     }
 
-    public Integer getRtmpPort() {
+    public int getRtmpPort() {
         return rtmpPort;
+    }
+
+    @Override
+    public void setRtmpPort(int rtmpPort) {
+
     }
 
     public void setRtmpPort(Integer rtmpPort) {
         this.rtmpPort = rtmpPort;
     }
 
-    public Integer getRtmpSSlPort() {
+    public int getRtmpSSlPort() {
         return rtmpSSlPort;
+    }
+
+    @Override
+    public void setRtmpSSlPort(int rtmpSSlPort) {
+
     }
 
     public void setRtmpSSlPort(Integer rtmpSSlPort) {
         this.rtmpSSlPort = rtmpSSlPort;
     }
 
-    public Integer getRtpProxyPort() {
-        return rtpProxyPort;
+    public int getRtpProxyPort() {
+        if (rtpProxyPort == null) {
+            return 0;
+        }else {
+            return rtpProxyPort;
+        }
+
+    }
+
+    @Override
+    public void setRtpProxyPort(int rtpProxyPort) {
+
     }
 
     public void setRtpProxyPort(Integer rtpProxyPort) {
         this.rtpProxyPort = rtpProxyPort;
     }
 
-    public Integer getRtspPort() {
+    public int getRtspPort() {
         return rtspPort;
+    }
+
+    @Override
+    public void setRtspPort(int rtspPort) {
+
     }
 
     public void setRtspPort(Integer rtspPort) {
         this.rtspPort = rtspPort;
     }
 
-    public Integer getRtspSSLPort() {
+    public int getRtspSSLPort() {
         return rtspSSLPort;
+    }
+
+    @Override
+    public void setRtspSSLPort(int rtspSSLPort) {
+
     }
 
     public void setRtspSSLPort(Integer rtspSSLPort) {
@@ -202,11 +256,101 @@
         this.rtpPortRange = rtpPortRange;
     }
 
-    public Integer getRecordAssistPort() {
+    public int getRecordAssistPort() {
         return recordAssistPort;
+    }
+
+    @Override
+    public void setRecordAssistPort(int recordAssistPort) {
+
     }
 
     public void setRecordAssistPort(Integer recordAssistPort) {
         this.recordAssistPort = recordAssistPort;
     }
+
+    @Override
+    public boolean isDocker() {
+        return docker;
+    }
+
+    @Override
+    public void setDocker(boolean docker) {
+        this.docker = docker;
+    }
+
+    public String getSdpIp() {
+        if (StringUtils.isEmpty(sdpIp)){
+            return ip;
+        }else {
+            return sdpIp;
+        }
+    }
+
+    public String getStreamIp() {
+        if (StringUtils.isEmpty(streamIp)){
+            return ip;
+        }else {
+            return streamIp;
+        }
+    }
+
+
+
+    public MediaServerItem getMediaSerItem(){
+        MediaServerItem mediaServerItem = new MediaServerItem();
+        mediaServerItem.setId(id);
+        mediaServerItem.setIp(ip);
+        mediaServerItem.setDocker(true);
+        mediaServerItem.setHookIp(hookIp);
+        mediaServerItem.setSdpIp(sdpIp);
+        mediaServerItem.setStreamIp(streamIp);
+        mediaServerItem.setHttpPort(httpPort);
+        mediaServerItem.setHttpSSlPort(httpSSlPort);
+        mediaServerItem.setRtmpPort(rtmpPort);
+        mediaServerItem.setRtmpSSlPort(rtmpSSlPort);
+        mediaServerItem.setRtpProxyPort(rtpProxyPort);
+        mediaServerItem.setRtspPort(rtspPort);
+        mediaServerItem.setRtspSSLPort(rtspSSLPort);
+        mediaServerItem.setAutoConfig(autoConfig);
+        mediaServerItem.setSecret(secret);
+        mediaServerItem.setStreamNoneReaderDelayMS(streamNoneReaderDelayMS);
+        mediaServerItem.setRtpEnable(rtpEnable);
+        mediaServerItem.setRtpPortRange(rtpPortRange);
+        mediaServerItem.setRecordAssistPort(recordAssistPort);
+        mediaServerItem.setCreateTime(createTime);
+        mediaServerItem.setUpdateTime(updateTime);
+        mediaServerItem.setCount(count);
+        return mediaServerItem;
+    }
+
+    @Override
+    public String getUpdateTime() {
+        return updateTime;
+    }
+
+    @Override
+    public void setUpdateTime(String updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    @Override
+    public String getCreateTime() {
+        return createTime;
+    }
+
+    @Override
+    public void setCreateTime(String createTime) {
+        this.createTime = createTime;
+    }
+
+    @Override
+    public int getCount() {
+        return count;
+    }
+
+    @Override
+    public void setCount(int count) {
+        this.count = count;
+    }
 }
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 3c4ea17..c543e6e 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
@@ -1,12 +1,16 @@
 package com.genersoft.iot.vmp.conf;
 
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.service.IMediaServerService;
+import org.apache.catalina.connector.ClientAbortException;
+import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
-import org.apache.catalina.connector.ClientAbortException;
 import org.mitre.dsmiley.httpproxy.ProxyServlet;
 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.boot.web.servlet.ServletRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -24,13 +28,16 @@
     private final static Logger logger = LoggerFactory.getLogger(ProxyServletConfig.class);
 
     @Autowired
-    private MediaConfig mediaConfig;
+    private IMediaServerService mediaServerService;
+
+    @Value("${server.port}")
+    private int serverPort;
 
     @Bean
     public ServletRegistrationBean zlmServletRegistrationBean(){
         ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ZLMProxySerlet(),"/zlm/*");
         servletRegistrationBean.setName("zlm_Proxy");
-        servletRegistrationBean.addInitParameter("targetUri", String.format("http://%s:%s", mediaConfig.getIp(), mediaConfig.getHttpPort()));
+        servletRegistrationBean.addInitParameter("targetUri", "http://127.0.0.1:6080");
         servletRegistrationBean.addUrlMappings();
         if (logger.isDebugEnabled()) {
             servletRegistrationBean.addInitParameter("log", "true");
@@ -38,24 +45,26 @@
         return servletRegistrationBean;
     }
 
-    class  ZLMProxySerlet extends ProxyServlet{
-
-
-
+    class ZLMProxySerlet extends ProxyServlet{
         @Override
         protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
             String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
-            if (!StringUtils.isEmpty(queryStr)) {
-                queryStr += "&secret=" + mediaConfig.getSecret();
-            }else {
-                queryStr = "secret=" + mediaConfig.getSecret();
+            IMediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
+            if (mediaInfo != null) {
+                if (!StringUtils.isEmpty(queryStr)) {
+                    queryStr += "&secret=" + mediaInfo.getSecret();
+                }else {
+                    queryStr = "secret=" + mediaInfo.getSecret();
+                }
             }
             return queryStr;
         }
 
+        /**
+         * 寮傚父澶勭悊
+         */
         @Override
         protected void handleRequestException(HttpRequest proxyRequest, HttpResponse proxyResonse, Exception e){
-            //System.out.println(e.getMessage());
             try {
                 super.handleRequestException(proxyRequest, proxyResonse, e);
             } catch (ServletException servletException) {
@@ -72,6 +81,64 @@
                 logger.error("zlm 浠g悊澶辫触锛� ", e);
             }
         }
+
+        /**
+         * 瀵逛簬涓烘寜鐓ф牸寮忚姹傜殑鍙互鐩存帴杩斿洖404
+         */
+        @Override
+        protected String getTargetUri(HttpServletRequest servletRequest) {
+            String requestURI = servletRequest.getRequestURI();
+            IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
+
+            String uri = null;
+            if (mediaInfo != null) {
+//                String realRequestURI = requestURI.substring(requestURI.indexOf(mediaInfo.getId())+ mediaInfo.getId().length());
+                uri = String.format("http://%s:%s", mediaInfo.getIp(), mediaInfo.getHttpPort());
+            }else {
+                uri = "http://127.0.0.1:" + serverPort +"/index/hook/null"; // 鍙槸涓�涓兘杩斿洖404鐨勮姹傝�屽凡锛� 鍏朵粬鐨勪篃鍙互
+            }
+            return uri;
+        }
+
+        /**
+         * 鍔ㄦ�佹浛鎹㈣姹傜洰鏍�
+         */
+        @Override
+        protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
+            String requestURI = servletRequest.getRequestURI();
+            IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
+            HttpHost host;
+            if (mediaInfo != null) {
+                host = new HttpHost(mediaInfo.getIp(), mediaInfo.getHttpPort());
+            }else {
+                host = new HttpHost("127.0.0.1", serverPort);
+            }
+            return host;
+
+        }
+
+        /**
+         * 鏍规嵁uri鑾峰彇娴佸獟浣撲俊鎭�
+         */
+        IMediaServerItem getMediaInfoByUri(String uri){
+            String[] split = uri.split("/");
+            String mediaServerId = split[2];
+            return mediaServerService.getOne(mediaServerId);
+        }
+
+        /**
+         * 鍘绘帀url涓殑鏍囧織淇℃伅
+         */
+        @Override
+        protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
+            String requestURI = servletRequest.getRequestURI();
+            IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
+            String url = super.rewriteUrlFromRequest(servletRequest);
+            if (mediaInfo == null) {
+                return  url;
+            }
+            return url.replace(mediaInfo.getId() + "/", "");
+        }
     }
 
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
index 0dca4af..0a76f69 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -95,20 +95,43 @@
 			tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "TCP");
 			tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint);
 			tcpSipProvider.addSipListener(this);
-			logger.info("Sip Server TCP 鍚姩鎴愬姛 port {" + sipConfig.getSipPort() + "}");
-		} catch (TransportNotSupportedException | InvalidArgumentException | TooManyListenersException | ObjectInUseException e) {
-			logger.error(String.format("鍒涘缓SIP鏈嶅姟澶辫触: %s", e.getMessage()));
+			logger.info("Sip Server TCP 鍚姩鎴愬姛 port {" + sipConfig.getMonitorIp() + ":" + sipConfig.getSipPort() + "}");
+//		} catch (TransportNotSupportedException | InvalidArgumentException | TooManyListenersException | ObjectInUseException e) {
+//			logger.error(String.format("鍒涘缓SIP鏈嶅姟澶辫触: %s", e.getMessage()));
+//		}
+		} catch (TransportNotSupportedException e) {
+			e.printStackTrace();
+		} catch (InvalidArgumentException e) {
+			logger.error("鏃犳硶浣跨敤 [ {}:{} ]浣滀负SIP[ TCP ]鏈嶅姟锛屽彲鎺掓煡: 1. sip.monitor-ip 鏄惁涓烘湰鏈虹綉鍗P; 2. sip.port 鏄惁宸茶鍗犵敤"
+					, sipConfig.getMonitorIp(), sipConfig.getSipPort());
+		} catch (TooManyListenersException e) {
+			e.printStackTrace();
+		} catch (ObjectInUseException e) {
+			e.printStackTrace();
 		}
 		return tcpSipProvider;
 	}
 	
 	@Bean("udpSipProvider")
 	@DependsOn("sipStack")
-	private SipProvider startUdpListener() throws Exception {
-		ListeningPoint udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "UDP");
-		SipProvider udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
-		udpSipProvider.addSipListener(this);
-		logger.info("Sip Server UDP 鍚姩鎴愬姛 port {" + sipConfig.getSipPort() + "}");
+	private SipProvider startUdpListener() {
+		ListeningPoint udpListeningPoint = null;
+		SipProvider udpSipProvider = null;
+		try {
+			udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "UDP");
+			udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
+			udpSipProvider.addSipListener(this);
+		} catch (TransportNotSupportedException e) {
+			e.printStackTrace();
+		} catch (InvalidArgumentException e) {
+			logger.error("鏃犳硶浣跨敤 [ {}:{} ]浣滀负SIP[ UDP ]鏈嶅姟锛屽彲鎺掓煡: 1. sip.monitor-ip 鏄惁涓烘湰鏈虹綉鍗P; 2. sip.port 鏄惁宸茶鍗犵敤"
+					, sipConfig.getMonitorIp(), sipConfig.getSipPort());
+		} catch (TooManyListenersException e) {
+			e.printStackTrace();
+		} catch (ObjectInUseException e) {
+			e.printStackTrace();
+		}
+		logger.info("Sip Server UDP 鍚姩鎴愬姛 port [" + sipConfig.getMonitorIp() + ":" + sipConfig.getSipPort() + "]");
 		return udpSipProvider;
 	}
 
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
index 6f3d4d7..cf939cf 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
@@ -94,6 +94,11 @@
 	 */
 	private String updateTime;
 
+	/**
+	 * 璁惧浣跨敤鐨勫獟浣搃d, 榛樿涓簄ull
+	 */
+	private String mediaServerId;
+
 	public String getDeviceId() {
 		return deviceId;
 	}
@@ -229,4 +234,12 @@
 	public void setUpdateTime(String updateTime) {
 		this.updateTime = updateTime;
 	}
+
+	public String getMediaServerId() {
+		return mediaServerId;
+	}
+
+	public void setMediaServerId(String mediaServerId) {
+		this.mediaServerId = mediaServerId;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java
index fd46947..a1ce8ca 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java
@@ -9,6 +9,7 @@
     private String stream;
     private String gbId;
     private String name;
+    private String mediaServerId;
     private double longitude;
     private double latitude;
     private String streamType;
@@ -77,4 +78,12 @@
     public void setStatus(boolean status) {
         this.status = status;
     }
+
+    public String getMediaServerId() {
+        return mediaServerId;
+    }
+
+    public void setMediaServerId(String mediaServerId) {
+        this.mediaServerId = mediaServerId;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
index 15e6f1e..2c9c494 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
@@ -66,6 +66,11 @@
      */
     private int localPort;
 
+    /**
+     * 浣跨敤鐨勬祦濯掍綋
+     */
+    private String mediaServerId;
+
     public String getIp() {
         return ip;
     }
@@ -161,4 +166,12 @@
     public void setTcpActive(boolean tcpActive) {
         this.tcpActive = tcpActive;
     }
+
+    public String getMediaServerId() {
+        return mediaServerId;
+    }
+
+    public void setMediaServerId(String mediaServerId) {
+        this.mediaServerId = mediaServerId;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java
index a475a1b..aed2100 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java
@@ -6,6 +6,9 @@
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import org.slf4j.Logger;
@@ -32,6 +35,8 @@
     private IVideoManagerStorager storager;
     @Autowired
     private IRedisCatchStorage redisCatchStorage;
+    @Autowired
+    private IMediaServerService mediaServerService;
 
     @Autowired
     private SIPCommanderFroPlatform sipCommanderFroPlatform;
@@ -62,22 +67,24 @@
             logger.info("鍋滄[ {} ]鐨勬墍鏈夋帹娴�", event.getPlatformGbID());
             StringBuilder app = new StringBuilder();
             StringBuilder stream = new StringBuilder();
-            for (int i = 0; i < sendRtpItems.size(); i++) {
+            for (SendRtpItem sendRtpItem : sendRtpItems) {
                 if (app.length() != 0) {
                     app.append(",");
                 }
-                app.append(sendRtpItems.get(i).getApp());
+                app.append(sendRtpItem.getApp());
                 if (stream.length() != 0) {
                     stream.append(",");
                 }
-                stream.append(sendRtpItems.get(i).getStreamId());
-                redisCatchStorage.deleteSendRTPServer(event.getPlatformGbID(), sendRtpItems.get(i).getChannelId());
+                stream.append(sendRtpItem.getStreamId());
+                redisCatchStorage.deleteSendRTPServer(event.getPlatformGbID(), sendRtpItem.getChannelId());
+                IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+                Map<String, Object> param = new HashMap<>();
+                param.put("vhost", "__defaultVhost__");
+                param.put("app", app.toString());
+                param.put("stream", stream.toString());
+                zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
             }
-            Map<String, Object> param = new HashMap<>();
-            param.put("vhost","__defaultVhost__");
-            param.put("app", app.toString());
-            param.put("stream", stream.toString());
-            zlmrtpServerFactory.stopSendRtpStream(param);
+
 
         }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
index dcfbf57..e2ff0f4 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
@@ -9,6 +9,7 @@
 
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
 import com.genersoft.iot.vmp.service.IPlayService;
@@ -104,6 +105,9 @@
 	@Autowired
 	private ZLMRTPServerFactory zlmrtpServerFactory;
 
+	@Autowired
+	private IMediaServerService mediaServerService;
+
 
 	// 娉細杩欓噷浣跨敤娉ㄨВ浼氬鑷村惊鐜緷璧栨敞鍏ワ紝鏆傜敤springBean
 	private SipProvider tcpSipProvider;
@@ -128,6 +132,7 @@
 			processor.setStorager(storager);
 			processor.setRedisCatchStorage(redisCatchStorage);
 			processor.setZlmrtpServerFactory(zlmrtpServerFactory);
+			processor.setMediaServerService(mediaServerService);
 			return processor;
 		} else if (Request.REGISTER.equals(method)) {
 			RegisterRequestProcessor processor = new RegisterRequestProcessor();
@@ -148,6 +153,7 @@
 			processor.setRequestEvent(evt);
 			processor.setRedisCatchStorage(redisCatchStorage);
 			processor.setZlmrtpServerFactory(zlmrtpServerFactory);
+			processor.setMediaServerService(mediaServerService);
 			return processor;
 		} else if (Request.BYE.equals(method)) {
 			ByeRequestProcessor processor = new ByeRequestProcessor();
@@ -155,6 +161,7 @@
 			processor.setRedisCatchStorage(redisCatchStorage);
 			processor.setZlmrtpServerFactory(zlmrtpServerFactory);
 			processor.setSIPCommander(cmder);
+			processor.setMediaServerService(mediaServerService);
 			return processor;
 		} else if (Request.CANCEL.equals(method)) {
 			CancelRequestProcessor processor = new CancelRequestProcessor();
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 4e111d6..b06fa77 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -3,6 +3,8 @@
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 
 /**    
  * @Description:璁惧鑳藉姏鎺ュ彛锛岀敤浜庡畾涔夎澶囩殑鎺у埗銆佹煡璇㈣兘鍔�   
@@ -90,7 +92,7 @@
 	 * @param device  瑙嗛璁惧
 	 * @param channelId  棰勮閫氶亾
 	 */
-	void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
+	void playStreamCmd(IMediaServerItem mediaServerItem, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
 	
 	/**
 	 * 璇锋眰鍥炴斁瑙嗛娴�
@@ -100,7 +102,7 @@
 	 * @param startTime 寮�濮嬫椂闂�,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 */
-	void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
+	void playbackStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
 	
 	/**
 	 * 瑙嗛娴佸仠姝�
@@ -288,12 +290,4 @@
 	 * @return				true = 鍛戒护鍙戦�佹垚鍔�
 	 */
 	boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime);
-
-
-	/**
-	 * 閲婃斁rtpserver
-	 * @param device
-	 * @param channelId
-	 */
-    void closeRTPServer(Device device, String channelId);
 }
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 2c9339c..5c2fa32 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -13,11 +13,10 @@
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.MediaConfig;
 import com.genersoft.iot.vmp.conf.UserSetup;
-import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
+import com.genersoft.iot.vmp.media.zlm.*;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
-import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
-import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import gov.nist.javax.sip.message.SIPRequest;
@@ -37,6 +36,7 @@
 import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
 import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
 import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
+import org.springframework.util.StringUtils;
 
 /**    
  * @Description:璁惧鑳藉姏鎺ュ彛锛岀敤浜庡畾涔夎澶囩殑鎺у埗銆佹煡璇㈣兘鍔�   
@@ -76,12 +76,6 @@
 
 	@Autowired
 	private ZLMRTPServerFactory zlmrtpServerFactory;
-
-	@Autowired
-	private ZLMRESTfulUtils zlmresTfulUtils;
-
-	@Autowired
-	private MediaConfig mediaConfig;
 
 	@Autowired
 	private UserSetup userSetup;
@@ -340,48 +334,45 @@
 	  * @param errorEvent sip閿欒璁㈤槄
 	  */
 	@Override
-	public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
+	public void playStreamCmd(IMediaServerItem mediaServerItem, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
 		String streamId = null;
 		try {
 			if (device == null) return;
+			String streamMode = device.getStreamMode().toUpperCase();
+
 			String ssrc = streamSession.createPlaySsrc();
-			if (mediaConfig.isRtpEnable()) {
+			if (mediaServerItem.isRtpEnable()) {
 				streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
 			}else {
 				streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
 			}
-			String streamMode = device.getStreamMode().toUpperCase();
-			ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
-			if (mediaInfo == null) {
-				logger.warn("鐐规挱鏃跺彂鐜癦LM灏氭湭杩炴帴...");
-				return;
-			}
 			Integer mediaPort = null;
 			// 浣跨敤鍔ㄦ�乽dp绔彛
-			if (mediaConfig.isRtpEnable()) {
-				mediaPort = zlmrtpServerFactory.createRTPServer(streamId);
+			if (mediaServerItem.isRtpEnable()) {
+				mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId);
 			}else {
-				mediaPort = mediaInfo.getRtpProxyPort();
+				mediaPort = mediaServerItem.getRtpProxyPort();
 			}
-
+			logger.info("{} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort);
 			// 娣诲姞璁㈤槄
 			JSONObject subscribeKey = new JSONObject();
 			subscribeKey.put("app", "rtp");
 			subscribeKey.put("stream", streamId);
 			subscribeKey.put("regist", true);
-
-			subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, json->{
+			subscribeKey.put("mediaServerId", mediaServerItem.getId());
+			subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
+					(IMediaServerItem mediaServerItemInUse, JSONObject json)->{
 				if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
-				event.response(json);
+				event.response(mediaServerItemInUse, json);
 				subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
 			});
 			//
 			StringBuffer content = new StringBuffer(200);
 			content.append("v=0\r\n");
 //			content.append("o=" + sipConfig.getSipId() + " 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
-			content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
+			content.append("o="+"00000"+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
 			content.append("s=Play\r\n");
-			content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
+			content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
 			content.append("t=0 0\r\n");
 
 			if (userSetup.isSeniorSdp()) {
@@ -459,21 +450,32 @@
 	 * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 */ 
 	@Override
-	public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
+	public void playbackStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
 			, SipSubscribe.Event errorEvent) {
 		try {
-			ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
 			String ssrc = streamSession.createPlayBackSsrc();
 			String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
+
+			Integer mediaPort = null;
+			// 浣跨敤鍔ㄦ�乽dp绔彛
+			if (mediaServerItem.isRtpEnable()) {
+				mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId);
+			}else {
+				mediaPort = mediaServerItem.getRtpProxyPort();
+			}
+			logger.info("{} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort);
+
 			// 娣诲姞璁㈤槄
 			JSONObject subscribeKey = new JSONObject();
 			subscribeKey.put("app", "rtp");
 			subscribeKey.put("stream", streamId);
 			subscribeKey.put("regist", true);
+			subscribeKey.put("mediaServerId", mediaServerItem.getId());
 			logger.debug("褰曞儚鍥炴斁娣诲姞璁㈤槄锛岃闃呭唴瀹癸細" + subscribeKey.toString());
-			subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, json->{
+			subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
+					(IMediaServerItem mediaServerItemInUse, JSONObject json)->{
 				if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
-				event.response(json);
+				event.response(mediaServerItemInUse, json);
 				subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
 			});
 
@@ -482,16 +484,12 @@
 	        content.append("o="+sipConfig.getSipId()+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n");
 	        content.append("s=Playback\r\n");
 	        content.append("u="+channelId+":0\r\n");
-	        content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
+	        content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
 	        content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
 					+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
-			Integer mediaPort = null;
-			// 浣跨敤鍔ㄦ�乽dp绔彛
-			if (mediaConfig.isRtpEnable()) {
-				mediaPort = zlmrtpServerFactory.createRTPServer(streamId);
-			}else {
-				mediaPort = mediaInfo.getRtpProxyPort();
-			}
+
+
+
 			String streamMode = device.getStreamMode().toUpperCase();
 
 			if (userSetup.isSeniorSdp()) {
@@ -560,56 +558,63 @@
 
 
 	/**
-	 * 瑙嗛娴佸仠姝�
-	 * 
+	 * 瑙嗛娴佸仠姝�, 涓嶄娇鐢ㄥ洖璋�
 	 */
 	@Override
 	public void streamByeCmd(String deviceId, String channelId) {
 		streamByeCmd(deviceId, channelId, null);
 	}
+
+	/**
+	 * 瑙嗛娴佸仠姝�
+	 */
 	@Override
 	public void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent) {
-		
+		StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
 		try {
 			ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId);
 			// 鏈嶅姟閲嶅惎鍚�, 鏃犳硶鐩存帴鍙戦�乥ye锛� 閫氳繃鎵嬪姩鏋勫缓鍙戦��
+//			if (transaction == null) {
+//
+//				if (streamInfo != null) {
+//					MediaServerItem mediaServerItem = redisCatchStorage.getMediaInfo(streamInfo.getMediaServerId());
+//					JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaServerItem,streamInfo.getApp(), streamInfo.getStreamId());
+//					if (mediaList != null) { // 浠嶅湪鎺ㄦ祦鎵嶅彂閫�
+//						if (mediaList.getInteger("code") == 0) {
+//							JSONArray data = mediaList.getJSONArray("data");
+//							if (data != null && data.size() > 0) {
+//								Device device = storager.queryVideoDevice(deviceId);
+//								if (device != null) {
+//									StreamInfo.TransactionInfo transactionInfo = streamInfo.getTransactionInfo();
+//									try {
+//										Request byteRequest = headerProvider.createByteRequest(device, channelId,
+//												transactionInfo.branch,
+//												transactionInfo.localTag,
+//												transactionInfo.remoteTag,
+//												transactionInfo.callId);
+//										transmitRequest(device, byteRequest);
+//									} catch (InvalidArgumentException e) {
+//										e.printStackTrace();
+//									}
+//								}
+//							}
+//						}
+//					}
+//					redisCatchStorage.stopPlay(streamInfo);
+//				}
+//
+//				if (okEvent != null) {
+//					okEvent.response(null);
+//				}
+//				return;
+//			}
 			if (transaction == null) {
-
-				StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
-				if (streamInfo != null) {
-					JSONObject mediaList = zlmresTfulUtils.getMediaList(streamInfo.getApp(), streamInfo.getStreamId());
-					if (mediaList != null) { // 浠嶅湪鎺ㄦ祦鎵嶅彂閫�
-						if (mediaList.getInteger("code") == 0) {
-							JSONArray data = mediaList.getJSONArray("data");
-							if (data != null && data.size() > 0) {
-								Device device = storager.queryVideoDevice(deviceId);
-								if (device != null) {
-									StreamInfo.TransactionInfo transactionInfo = streamInfo.getTransactionInfo();
-									try {
-										Request byteRequest = headerProvider.createByteRequest(device, channelId,
-												transactionInfo.branch,
-												transactionInfo.localTag,
-												transactionInfo.remoteTag,
-												transactionInfo.callId);
-										transmitRequest(device, byteRequest);
-									} catch (InvalidArgumentException e) {
-										e.printStackTrace();
-									}
-								}
-							}
-						}
-					}
-					redisCatchStorage.stopPlay(streamInfo);
-				}
-
-				if (okEvent != null) {
-					okEvent.response(null);
-				}
+				logger.warn("[ {} -> {}]鍋滄瑙嗛娴佺殑鏃跺�欏彂鐜颁簨鍔″凡涓㈠け", deviceId, channelId);
 				return;
 			}
-			
 			Dialog dialog = transaction.getDialog();
 			if (dialog == null) {
+				logger.warn("[ {} -> {}]鍋滄瑙嗛娴佺殑鏃跺�欏彂鐜板璇濆凡涓㈠け", deviceId, channelId);
 				return;
 			}
 			Request byeRequest = dialog.createRequest(Request.BYE);
@@ -632,7 +637,7 @@
 			}
 
 			dialog.sendRequest(clientTransaction);
-			zlmrtpServerFactory.closeRTPServer(streamSession.getStreamId(deviceId, channelId));
+
 			streamSession.remove(deviceId, channelId);
 		} catch (SipException | ParseException e) {
 			e.printStackTrace();
@@ -721,7 +726,7 @@
 			cmdXml.append("<Control>\r\n");
 			cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
 			cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
-			if (XmlUtil.isEmpty(channelId)) {
+			if (StringUtils.isEmpty(channelId)) {
 				cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
 			} else {
 				cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@@ -821,16 +826,16 @@
 			cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
 			cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
 			cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
-			if (!XmlUtil.isEmpty(alarmMethod) || !XmlUtil.isEmpty(alarmType)) {
+			if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
 				cmdXml.append("<Info>\r\n");
 			}
-			if (!XmlUtil.isEmpty(alarmMethod)) {
+			if (!StringUtils.isEmpty(alarmMethod)) {
 				cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
 			}
-			if (!XmlUtil.isEmpty(alarmType)) {
+			if (!StringUtils.isEmpty(alarmType)) {
 				cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
 			}
-			if (!XmlUtil.isEmpty(alarmMethod) || !XmlUtil.isEmpty(alarmType)) {
+			if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
 				cmdXml.append("</Info>\r\n");
 			}
 			cmdXml.append("</Control>\r\n");
@@ -863,7 +868,7 @@
 			cmdXml.append("<Control>\r\n");
 			cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
 			cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
-			if (XmlUtil.isEmpty(channelId)) {
+			if (StringUtils.isEmpty(channelId)) {
 				cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
 			} else {
 				cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@@ -901,7 +906,7 @@
 			cmdXml.append("<Control>\r\n");
 			cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
 			cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
-			if (XmlUtil.isEmpty(channelId)) {
+			if (StringUtils.isEmpty(channelId)) {
 				cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
 			} else {
 				cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@@ -969,13 +974,13 @@
 			cmdXml.append("<Control>\r\n");
 			cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
 			cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
-			if (XmlUtil.isEmpty(channelId)) {
+			if (StringUtils.isEmpty(channelId)) {
 				cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
 			} else {
 				cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
 			}
 			cmdXml.append("<BasicParam>\r\n");
-			if (!XmlUtil.isEmpty(name)) {
+			if (!StringUtils.isEmpty(name)) {
 				cmdXml.append("<Name>" + name + "</Name>\r\n");
 			}
 			if (NumericUtil.isInteger(expiration)) {
@@ -1169,22 +1174,22 @@
 			cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
 			cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
 			cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
-			if (!XmlUtil.isEmpty(startPriority)) {
+			if (!StringUtils.isEmpty(startPriority)) {
 				cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
 			}
-			if (!XmlUtil.isEmpty(endPriority)) {
+			if (!StringUtils.isEmpty(endPriority)) {
 				cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
 			}
-			if (!XmlUtil.isEmpty(alarmMethod)) {
+			if (!StringUtils.isEmpty(alarmMethod)) {
 				cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
 			}
-			if (!XmlUtil.isEmpty(alarmType)) {
+			if (!StringUtils.isEmpty(alarmType)) {
 				cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
 			}
-			if (!XmlUtil.isEmpty(startTime)) {
+			if (!StringUtils.isEmpty(startTime)) {
 				cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
 			}
-			if (!XmlUtil.isEmpty(endTime)) {
+			if (!StringUtils.isEmpty(endTime)) {
 				cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
 			}
 			cmdXml.append("</Query>\r\n");
@@ -1218,7 +1223,7 @@
 			cmdXml.append("<Query>\r\n");
 			cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
 			cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
-			if (XmlUtil.isEmpty(channelId)) {
+			if (StringUtils.isEmpty(channelId)) {
 				cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
 			} else {
 				cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@@ -1253,7 +1258,7 @@
 			cmdXml.append("<Query>\r\n");
 			cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
 			cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
-			if (XmlUtil.isEmpty(channelId)) {
+			if (StringUtils.isEmpty(channelId)) {
 				cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
 			} else {
 				cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@@ -1365,22 +1370,22 @@
 			cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
 			cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
 			cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
-			if (!XmlUtil.isEmpty(startPriority)) {
+			if (!StringUtils.isEmpty(startPriority)) {
 				cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
 			}
-			if (!XmlUtil.isEmpty(endPriority)) {
+			if (!StringUtils.isEmpty(endPriority)) {
 				cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
 			}
-			if (!XmlUtil.isEmpty(alarmMethod)) {
+			if (!StringUtils.isEmpty(alarmMethod)) {
 				cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
 			}
-			if (!XmlUtil.isEmpty(alarmType)) {
+			if (!StringUtils.isEmpty(alarmType)) {
 				cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
 			}
-			if (!XmlUtil.isEmpty(startTime)) {
+			if (!StringUtils.isEmpty(startTime)) {
 				cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
 			}
-			if (!XmlUtil.isEmpty(endTime)) {
+			if (!StringUtils.isEmpty(endTime)) {
 				cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
 			}
 			cmdXml.append("</Query>\r\n");
@@ -1430,17 +1435,5 @@
 
 		clientTransaction.sendRequest();
 		return clientTransaction;
-	}
-
-
-
-
-	@Override
-	public void closeRTPServer(Device device, String channelId) {
-		if (mediaConfig.isRtpEnable()) {
-			String streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
-			zlmrtpServerFactory.closeRTPServer(streamId);
-		}
-		streamSession.remove(device.getDeviceId(), channelId);
 	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/SIPRequestAbstractProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/SIPRequestAbstractProcessor.java
index 5410820..12290d2 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/SIPRequestAbstractProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/SIPRequestAbstractProcessor.java
@@ -16,6 +16,8 @@
 import gov.nist.javax.sip.SipStackImpl;
 import gov.nist.javax.sip.message.SIPRequest;
 import gov.nist.javax.sip.stack.SIPServerTransaction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**    
  * @Description:澶勭悊鎺ユ敹IPCamera鍙戞潵鐨凷IP鍗忚璇锋眰娑堟伅
@@ -23,6 +25,8 @@
  * @date:   2020骞�5鏈�3鏃� 涓嬪崍4:42:22     
  */
 public abstract class SIPRequestAbstractProcessor implements ISIPRequestProcessor {
+
+	private final static Logger logger = LoggerFactory.getLogger(SIPRequestAbstractProcessor.class);
 
 	protected RequestEvent evt;
 	
@@ -64,9 +68,9 @@
 					}
 				}
 			} catch (TransactionAlreadyExistsException e) {
-				e.printStackTrace();
+				logger.error(e.getMessage());
 			} catch (TransactionUnavailableException e) {
-				e.printStackTrace();
+				logger.error(e.getMessage());
 			}
 		}
 		return serverTransaction;
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java
index 413f0d1..6f80971 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java
@@ -13,6 +13,9 @@
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
 import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -29,6 +32,8 @@
     private IRedisCatchStorage redisCatchStorage;
 
 	private ZLMRTPServerFactory zlmrtpServerFactory;
+
+	private IMediaServerService mediaServerService;
 
 	/**   
 	 * 澶勭悊  ACK璇锋眰
@@ -76,18 +81,22 @@
 			while (!rtpPushed) {
 				try {
 					if (System.currentTimeMillis() - startTime < 30 * 1000) {
-						if (zlmrtpServerFactory.isStreamReady(streamInfo.getApp(), streamInfo.getStreamId())) {
+						IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+						if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) {
 							rtpPushed = true;
-							logger.info("宸茶幏鍙栬澶囨帹娴侊紝寮�濮嬪悜涓婄骇鎺ㄦ祦");
-							zlmrtpServerFactory.startSendRtpStream(param);
+							logger.info("宸茶幏鍙栬澶囨帹娴乕{}/{}]锛屽紑濮嬪悜涓婄骇鎺ㄦ祦[{}:{}]",
+									streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort());
+							zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
 						} else {
-							logger.info("绛夊緟璁惧鎺ㄦ祦.......");
+							logger.info("绛夊緟璁惧鎺ㄦ祦[{}/{}].......",
+									streamInfo.getApp() ,streamInfo.getStreamId());
 							Thread.sleep(1000);
 							continue;
 						}
 					} else {
 						rtpPushed = true;
-						logger.info("璁惧鎺ㄦ祦瓒呮椂锛岀粓姝㈠悜涓婄骇鎺ㄦ祦");
+						logger.info("璁惧鎺ㄦ祦[{}/{}]瓒呮椂锛岀粓姝㈠悜涓婄骇鎺ㄦ祦",
+								streamInfo.getApp() ,streamInfo.getStreamId());
 					}
 				} catch (InterruptedException e) {
 					e.printStackTrace();
@@ -123,4 +132,12 @@
 	public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
 		this.zlmrtpServerFactory = zlmrtpServerFactory;
 	}
+
+	public IMediaServerService getMediaServerService() {
+		return mediaServerService;
+	}
+
+	public void setMediaServerService(IMediaServerService mediaServerService) {
+		this.mediaServerService = mediaServerService;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java
index fdb7c0b..50e8c32 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java
@@ -15,6 +15,9 @@
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
 import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,6 +41,8 @@
 
 	private ZLMRTPServerFactory zlmrtpServerFactory;
 
+	private IMediaServerService mediaServerService;
+
 	/**
 	 * 澶勭悊BYE璇锋眰
 	 * @param evt
@@ -60,9 +65,10 @@
 				param.put("stream",streamId);
 				param.put("ssrc",sendRtpItem.getSsrc());
 				logger.info("鍋滄鍚戜笂绾ф帹娴侊細" + streamId);
-				zlmrtpServerFactory.stopSendRtpStream(param);
+				IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+				zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
 				redisCatchStorage.deleteSendRTPServer(platformGbId, channelId);
-				if (zlmrtpServerFactory.totalReaderCount(sendRtpItem.getApp(), streamId) == 0) {
+				if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) {
 					logger.info(streamId + "鏃犲叾瀹冭鐪嬭�咃紝閫氱煡璁惧鍋滄鎺ㄦ祦");
 					cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId);
 				}
@@ -112,4 +118,11 @@
 		this.cmder = cmder;
 	}
 
+	public IMediaServerService getMediaServerService() {
+		return mediaServerService;
+	}
+
+	public void setMediaServerService(IMediaServerService mediaServerService) {
+		this.mediaServerService = mediaServerService;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
index 5f356b0..7219dbb 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
@@ -11,12 +11,16 @@
 import javax.sip.message.Request;
 import javax.sip.message.Response;
 
+import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
 import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
@@ -50,6 +54,8 @@
 	private IPlayService playService;
 
 	private ZLMRTPServerFactory zlmrtpServerFactory;
+
+	private IMediaServerService mediaServerService;
 
 	public ZLMRTPServerFactory getZlmrtpServerFactory() {
 		return zlmrtpServerFactory;
@@ -91,6 +97,7 @@
 				// 鏌ヨ骞冲彴涓嬫槸鍚︽湁璇ラ�氶亾
 				DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
 				GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
+				IMediaServerItem mediaServerItem = null;
 				// 涓嶆槸閫氶亾鍙兘鏄洿鎾祦
 				if (channel != null && gbStream == null ) {
 					if (channel.getStatus() == 0) {
@@ -100,8 +107,15 @@
 					}
 					responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 閫氶亾瀛樺湪锛屽彂181锛屽懠鍙浆鎺ヤ腑
 				}else if(channel == null && gbStream != null){
-					Boolean streamReady = zlmrtpServerFactory.isStreamReady(gbStream.getApp(), gbStream.getStream());
-					if (!streamReady) {
+					String mediaServerId = gbStream.getMediaServerId();
+					mediaServerItem = mediaServerService.getOne(mediaServerId);
+					if (mediaServerItem == null) {
+						logger.info("[ app={}, stream={} ]zlm鎵句笉鍒帮紝杩斿洖410",gbStream.getApp(), gbStream.getStream());
+						responseAck(evt, Response.GONE, "media server not found");
+						return;
+					}
+					Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
+					if (!streamReady ) {
 						logger.info("[ app={}, stream={} ]閫氶亾绂荤嚎锛岃繑鍥�400",gbStream.getApp(), gbStream.getStream());
 						responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
 						return;
@@ -130,8 +144,8 @@
 				//boolean recvonly = false;
 				boolean mediaTransmissionTCP = false;
 				Boolean tcpActive = null;
-				for (int i = 0; i < mediaDescriptions.size(); i++) {
-					MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
+				for (Object description : mediaDescriptions) {
+					MediaDescription mediaDescription = (MediaDescription) description;
 					Media media = mediaDescription.getMedia();
 
 					Vector mediaFormats = media.getMediaFormats(false);
@@ -147,7 +161,7 @@
 								mediaTransmissionTCP = true;
 								if ("active".equals(setup)) {
 									tcpActive = true;
-								}else if ("passive".equals(setup)) {
+								} else if ("passive".equals(setup)) {
 									tcpActive = false;
 								}
 							}
@@ -174,7 +188,13 @@
 						responseAck(evt, Response.SERVER_INTERNAL_ERROR);
 						return;
 					}
-					SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(addressStr, port, ssrc, requesterId,
+					mediaServerItem = playService.getNewMediaServerItem(device);
+					if (mediaServerItem == null) {
+						logger.warn("鏈壘鍒板彲鐢ㄧ殑zlm");
+						responseAck(evt, Response.BUSY_HERE);
+						return;
+					}
+					SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
 							device.getDeviceId(), channelId,
 							mediaTransmissionTCP);
 					if (tcpActive != null) {
@@ -189,18 +209,18 @@
 					// 鍐欏叆redis锛� 瓒呮椂鏃跺洖澶�
 					redisCatchStorage.updateSendRTPSever(sendRtpItem);
 					// 閫氱煡涓嬬骇鎺ㄦ祦锛�
-					PlayResult playResult = playService.play(device.getDeviceId(), channelId, (responseJSON)->{
+					PlayResult playResult = playService.play(mediaServerItem,device.getDeviceId(), channelId, (mediaServerItemInUSe, responseJSON)->{
 						// 鏀跺埌鎺ㄦ祦锛� 鍥炲200OK, 绛夊緟ack
 						// if (sendRtpItem == null) return;
 						sendRtpItem.setStatus(1);
 						redisCatchStorage.updateSendRTPSever(sendRtpItem);
 						// TODO 娣诲姞瀵箃cp鐨勬敮鎸�
-						ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
+
 						StringBuffer content = new StringBuffer(200);
 						content.append("v=0\r\n");
-						content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
+						content.append("o="+"00000"+" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
 						content.append("s=Play\r\n");
-						content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
+						content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
 						content.append("t=0 0\r\n");
 						content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
 						content.append("a=sendonly\r\n");
@@ -217,7 +237,7 @@
 						} catch (ParseException e) {
 							e.printStackTrace();
 						}
-					} ,(event -> {
+					} ,((event) -> {
 						// 鏈煡閿欒銆傜洿鎺ヨ浆鍙戣澶囩偣鎾殑閿欒
 						Response response = null;
 						try {
@@ -232,7 +252,7 @@
 					}
 
 				}else if (gbStream != null) {
-					SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(addressStr, port, ssrc, requesterId,
+					SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
 							gbStream.getApp(), gbStream.getStream(), channelId,
 							mediaTransmissionTCP);
 
@@ -251,12 +271,11 @@
 					sendRtpItem.setStatus(1);
 					redisCatchStorage.updateSendRTPSever(sendRtpItem);
 					// TODO 娣诲姞瀵箃cp鐨勬敮鎸�
-					ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
 					StringBuffer content = new StringBuffer(200);
 					content.append("v=0\r\n");
-					content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
+					content.append("o="+"00000"+" 0 0 IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
 					content.append("s=Play\r\n");
-					content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
+					content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
 					content.append("t=0 0\r\n");
 					content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
 					content.append("a=sendonly\r\n");
@@ -444,4 +463,12 @@
 	public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
 		this.redisCatchStorage = redisCatchStorage;
 	}
+
+	public IMediaServerService getMediaServerService() {
+		return mediaServerService;
+	}
+
+	public void setMediaServerService(IMediaServerService mediaServerService) {
+		this.mediaServerService = mediaServerService;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
index 9d282c6..70e64a5 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
@@ -282,7 +282,7 @@
 			//String result = XmlUtil.getText(rootElement, "Result");
 			// 鍥炲200 OK
 			responseAck(evt);
-			if (rootElement.getName().equals("Response")) {//} !XmlUtil.isEmpty(result)) {
+			if (rootElement.getName().equals("Response")) {//} !StringUtils.isEmpty(result)) {
 				// 姝ゅ鏄鏈钩鍙板彂鍑篋eviceControl鎸囦护鐨勫簲绛�
 				JSONObject json = new JSONObject();
 				XmlUtil.node2Json(rootElement, json);
@@ -299,7 +299,7 @@
 				String platformId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
 				String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
 				// 杩滅▼鍚姩鍔熻兘
-				if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement, "TeleBoot"))) {
+				if (!StringUtils.isEmpty(XmlUtil.getText(rootElement, "TeleBoot"))) {
 					if (deviceId.equals(targetGBId)) {
 						// 杩滅▼鍚姩鏈钩鍙帮細闇�瑕佸湪閲嶆柊鍚姩绋嬪簭鍚庡厛瀵筍ipStack瑙g粦
 						logger.info("鎵ц杩滅▼鍚姩鏈钩鍙板懡浠�");
@@ -337,7 +337,7 @@
 					}
 				}
 				// 浜戝彴/鍓嶇鎺у埗鍛戒护
-				if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement,"PTZCmd")) && !deviceId.equals(targetGBId)) {
+				if (!StringUtils.isEmpty(XmlUtil.getText(rootElement,"PTZCmd")) && !deviceId.equals(targetGBId)) {
 					String cmdString = XmlUtil.getText(rootElement,"PTZCmd");
 					Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, deviceId);
 					cmder.fronEndCmd(device, deviceId, cmdString);
@@ -421,7 +421,7 @@
 			String deviceId = XmlUtil.getText(rootElement, "DeviceID");
 			// 鍥炲200 OK
 			responseAck(evt);
-			if (rootElement.getName().equals("Response")) {//   !XmlUtil.isEmpty(result)) {
+			if (rootElement.getName().equals("Response")) {//   !StringUtils.isEmpty(result)) {
 				// 姝ゅ鏄鏈钩鍙板彂鍑篋eviceControl鎸囦护鐨勫簲绛�
 				JSONObject json = new JSONObject();
 				XmlUtil.node2Json(rootElement, json);
@@ -718,7 +718,7 @@
 					deviceAlarm.setLatitude(0.00);
 				}
 	
-				if (!XmlUtil.isEmpty(deviceAlarm.getAlarmMethod())) {
+				if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) {
 					if ( deviceAlarm.getAlarmMethod().equals("4")) {
 						MobilePosition mobilePosition = new MobilePosition();
 						mobilePosition.setDeviceId(deviceAlarm.getDeviceId());
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
index c82ba60..4220d81 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
@@ -17,6 +17,7 @@
 import org.dom4j.io.SAXReader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
 
 /**
  * 鍩轰簬dom4j鐨勫伐鍏峰寘
@@ -114,12 +115,12 @@
         // 濡傛灉鏄睘鎬�
         for (Object o : element.attributes()) {
             Attribute attr = (Attribute) o;
-            if (!isEmpty(attr.getValue())) {
+            if (!StringUtils.isEmpty(attr.getValue())) {
                 json.put("@" + attr.getName(), attr.getValue());
             }
         }
         List<Element> chdEl = element.elements();
-        if (chdEl.isEmpty() && !isEmpty(element.getText())) {// 濡傛灉娌℃湁瀛愬厓绱�,鍙湁涓�涓��
+        if (chdEl.isEmpty() && !StringUtils.isEmpty(element.getText())) {// 濡傛灉娌℃湁瀛愬厓绱�,鍙湁涓�涓��
             json.put(element.getName(), element.getText());
         }
 
@@ -150,7 +151,7 @@
             } else { // 瀛愬厓绱犳病鏈夊瓙鍏冪礌
                 for (Object o : element.attributes()) {
                     Attribute attr = (Attribute) o;
-                    if (!isEmpty(attr.getValue())) {
+                    if (!StringUtils.isEmpty(attr.getValue())) {
                         json.put("@" + attr.getName(), attr.getValue());
                     }
                 }
@@ -159,12 +160,5 @@
                 }
             }
         }
-    }
-
-    public static boolean isEmpty(String str) {
-        if (str == null || str.trim().isEmpty() || "null".equals(str)) {
-            return true;
-        }
-        return false;
     }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java
deleted file mode 100644
index a00bc2a..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java
+++ /dev/null
@@ -1,54 +0,0 @@
-//package com.genersoft.iot.vmp.media.zlm;
-//
-//import com.genersoft.iot.vmp.conf.MediaConfig;
-//import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
-//import org.springframework.beans.factory.annotation.Autowired;
-//import org.springframework.beans.factory.annotation.Value;
-//import org.springframework.web.bind.annotation.*;
-//import org.springframework.web.client.HttpClientErrorException;
-//import org.springframework.web.client.RestTemplate;
-//
-//import javax.servlet.http.HttpServletRequest;
-//import javax.servlet.http.HttpServletResponse;
-//
-//@RestController
-//@RequestMapping("/zlm")
-//public class ZLMHTTPProxyController {
-//
-//
-//    // private final static Logger logger = LoggerFactory.getLogger(ZLMHTTPProxyController.class);
-//
-//    @Autowired
-//    private IRedisCatchStorage redisCatchStorage;
-//
-//    @Autowired
-//    private MediaConfig mediaConfig;
-//
-//    @ResponseBody
-//    @RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8")
-//    public Object proxy(HttpServletRequest request, HttpServletResponse response){
-//
-//        if (redisCatchStorage.getMediaInfo() == null) {
-//            return "鏈帴鍏ユ祦濯掍綋";
-//        }
-//        ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
-//        String requestURI = String.format("http://%s:%s%s?%s&%s",
-//                mediaInfo.getLocalIP(),
-//                mediaConfig.getHttpPort(),
-//                request.getRequestURI().replace("/zlm",""),
-//                mediaInfo.getHookAdminParams(),
-//                request.getQueryString()
-//        );
-//        // 鍙戦�佽姹�
-//        RestTemplate restTemplate = new RestTemplate();
-//        //灏嗘寚瀹氱殑url杩斿洖鐨勫弬鏁拌嚜鍔ㄥ皝瑁呭埌鑷畾涔夊ソ鐨勫搴旂被瀵硅薄涓�
-//        Object result = null;
-//        try {
-//            result = restTemplate.getForObject(requestURI,Object.class);
-//
-//        }catch (HttpClientErrorException httpClientErrorException) {
-//            response.setStatus(httpClientErrorException.getStatusCode().value());
-//        }
-//        return result;
-//    }
-//}
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 bd8485d..b7aebf4 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -9,6 +9,9 @@
 import com.genersoft.iot.vmp.conf.MediaConfig;
 import com.genersoft.iot.vmp.conf.UserSetup;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.service.IPlayService;
@@ -53,10 +56,10 @@
 	private IRedisCatchStorage redisCatchStorage;
 
 	@Autowired
-	private ZLMRESTfulUtils zlmresTfulUtils;
+	private IMediaServerService mediaServerService;
 
 	@Autowired
-	private ZLMServerManger zlmServerManger;
+	private ZLMRESTfulUtils zlmresTfulUtils;
 
 	 @Autowired
 	 private ZLMMediaListManager zlmMediaListManager;
@@ -81,6 +84,7 @@
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_flow_report API璋冪敤锛屽弬鏁帮細" + json.toString());
 		}
+		String mediaServerId = json.getString("mediaServerId");
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
 		ret.put("msg", "success");
@@ -98,6 +102,7 @@
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_http_access API 璋冪敤锛屽弬鏁帮細" + json.toString());
 		}
+		String mediaServerId = json.getString("mediaServerId");
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
 		ret.put("err", "");
@@ -117,9 +122,14 @@
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_play API璋冪敤锛屽弬鏁帮細" + json.toString());
 		}
+		String mediaServerId = json.getString("mediaServerId");
 		ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_play, json);
 		if (subscribe != null ) {
-			subscribe.response(json);
+			IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
+			if (mediaInfo != null) {
+				subscribe.response(mediaInfo, json);
+			}
+
 		}
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
@@ -133,20 +143,25 @@
 	 */
 	@ResponseBody
 	@PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")
-	public ResponseEntity<String> onPublish(@RequestBody JSONObject json){
+	public ResponseEntity<String> onPublish(@RequestBody JSONObject json) {
 
 		logger.debug("ZLM HOOK on_publish API璋冪敤锛屽弬鏁帮細" + json.toString());
 
+		String mediaServerId = json.getString("mediaServerId");
 		ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
-		if (subscribe != null) subscribe.response(json);
-
+		if (subscribe != null) {
+			IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
+			if (mediaInfo != null) {
+				subscribe.response(mediaInfo, json);
+			}
+		}
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
 		ret.put("msg", "success");
 		ret.put("enableHls", true);
 		ret.put("enableMP4", userSetup.isRecordPushLive());
 		ret.put("enableRtxp", true);
-		return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
+		return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
 	}
 	
 	/**
@@ -160,6 +175,7 @@
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_record_mp4 API璋冪敤锛屽弬鏁帮細" + json.toString());
 		}
+		String mediaServerId = json.getString("mediaServerId");
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
 		ret.put("msg", "success");
@@ -177,6 +193,7 @@
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_rtsp_realm API璋冪敤锛屽弬鏁帮細" + json.toString());
 		}
+		String mediaServerId = json.getString("mediaServerId");
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
 		ret.put("realm", "");
@@ -195,6 +212,7 @@
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_rtsp_auth API璋冪敤锛屽弬鏁帮細" + json.toString());
 		}
+		String mediaServerId = json.getString("mediaServerId");
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
 		ret.put("encrypted", false);
@@ -216,9 +234,15 @@
 		// TODO 濡傛灉鏄甫鏈塺tpstream鍒欏紑鍚寜闇�鎷夋祦
 		// String app = json.getString("app");
 		// String stream = json.getString("stream");
-
+		String mediaServerId = json.getString("mediaServerId");
 		ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_shell_login, json);
-		if (subscribe != null) subscribe.response(json);
+		if (subscribe != null ) {
+			IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
+			if (mediaInfo != null) {
+				subscribe.response(mediaInfo, json);
+			}
+
+		}
 
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
@@ -237,9 +261,15 @@
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_stream_changed API璋冪敤锛屽弬鏁帮細" + json.toString());
 		}
-
+		String mediaServerId = json.getString("mediaServerId");
 		ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, json);
-		if (subscribe != null) subscribe.response(json);
+		if (subscribe != null ) {
+			IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
+			if (mediaInfo != null) {
+				subscribe.response(mediaInfo, json);
+			}
+
+		}
 
 		// 娴佹秷澶辩Щ闄edis play
 		String app = json.getString("app");
@@ -251,6 +281,11 @@
 			logger.info("[stream: " + streamId + "] on_stream_changed->>" + schema);
 		}
 		if ("rtmp".equals(schema)){
+			if (regist) {
+				mediaServerService.addCount(mediaServerId);
+			}else {
+				mediaServerService.removeCount(mediaServerId);
+			}
 			if ("rtp".equals(app) && !regist ) {
 				StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
 				if (streamInfo!=null){
@@ -262,10 +297,11 @@
 				}
 			}else {
 				if (!"rtp".equals(app) ){
+					IMediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
 					if (regist) {
-						zlmMediaListManager.addMedia(app, streamId);
+						zlmMediaListManager.addMedia(mediaServerItem, app, streamId);
 					}else {
-						zlmMediaListManager.removeMedia(app, streamId);
+						zlmMediaListManager.removeMedia( app, streamId);
 					}
 				}
 			}
@@ -288,7 +324,7 @@
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_stream_none_reader API璋冪敤锛屽弬鏁帮細" + json.toString());
 		}
-		
+		String mediaServerId = json.getString("mediaServerId");
 		String streamId = json.getString("stream");
 		String app = json.getString("app");
 
@@ -329,11 +365,12 @@
 	@ResponseBody
 	@PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8")
 	public ResponseEntity<String> onStreamNotFound(@RequestBody JSONObject json){
-		
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_stream_not_found API璋冪敤锛屽弬鏁帮細" + json.toString());
 		}
-		if (userSetup.isAutoApplyPlay()) {
+		String mediaServerId = json.getString("mediaServerId");
+		IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
+		if (userSetup.isAutoApplyPlay() && mediaInfo != null) {
 			String app = json.getString("app");
 			String streamId = json.getString("stream");
 			if ("rtp".equals(app) && streamId.contains("gb_play") ) {
@@ -344,9 +381,9 @@
 					Device device = storager.queryVideoDevice(deviceId);
 					if (device != null) {
 						UUID uuid = UUID.randomUUID();
-						cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
+						cmder.playStreamCmd(mediaInfo, device, channelId, (IMediaServerItem mediaServerItemInuse, JSONObject response) -> {
 							logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
-							playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
+							playService.onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid.toString());
 						}, null);
 					}
 
@@ -367,26 +404,19 @@
 	 */
 	@ResponseBody
 	@PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8")
-	public ResponseEntity<String> onServerStarted(HttpServletRequest request, @RequestBody JSONObject json){
+	public ResponseEntity<String> onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject){
 		
 		if (logger.isDebugEnabled()) {
-			logger.debug("ZLM HOOK on_server_started API璋冪敤锛屽弬鏁帮細" + json.toString());
+			logger.debug("ZLM HOOK on_server_started API璋冪敤锛屽弬鏁帮細" + jsonObject.toString());
 		}
-
-//		String data = json.getString("data");
-//		List<MediaServerConfig> mediaServerConfigs = JSON.parseArray(JSON.toJSONString(json), MediaServerConfig.class);
-//		MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0);
-
+		String remoteAddr = request.getRemoteAddr();
+		jsonObject.put("ip", remoteAddr);
 		List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_started);
-		if (subscribes != null && subscribes.size() > 0) {
+		if (subscribes != null  && subscribes.size() > 0) {
 			for (ZLMHttpHookSubscribe.Event subscribe : subscribes) {
-				subscribe.response(json);
+				subscribe.response(null, jsonObject);
 			}
 		}
-		ZLMServerConfig ZLMServerConfig = JSON.toJavaObject(json, ZLMServerConfig.class);
-		zlmServerManger.updateServerCatch(ZLMServerConfig);
-		// 閲嶆柊鍙戣捣浠g悊
-
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
 		ret.put("msg", "success");
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
index 4f832ae..62b18f5 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
@@ -1,6 +1,8 @@
 package com.genersoft.iot.vmp.media.zlm;
 
 import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import org.springframework.stereotype.Component;
 
 import java.util.*;
@@ -30,7 +32,7 @@
     }
 
     public interface Event{
-        void response(JSONObject response);
+        void response(IMediaServerItem mediaServerItem, JSONObject response);
     }
 
     private Map<HookType, Map<JSONObject, ZLMHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
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 ed407d2..3876309 100644
--- 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,6 +2,8 @@
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
@@ -45,11 +47,11 @@
     private ZLMHttpHookSubscribe subscribe;
 
 
-    public void updateMediaList() {
+    public void updateMediaList(MediaServerItem mediaServerItem) {
         storager.clearMediaList();
 
         // 浣跨敤寮傛鐨勫綋鏃舵洿鏂板獟浣撴祦鍒楄〃
-        zlmresTfulUtils.getMediaList((mediaList ->{
+        zlmresTfulUtils.getMediaList(mediaServerItem, (mediaList ->{
             if (mediaList == null) return;
             String dataStr = mediaList.getString("data");
 
@@ -57,10 +59,10 @@
             Map<String, StreamPushItem> result = new HashMap<>();
             List<StreamPushItem> streamPushItems = null;
             // 鑾峰彇鎵�鏈夌殑鍥芥爣鍏宠仈
-            List<GbStream> gbStreams = gbStreamMapper.selectAll();
+//            List<GbStream> gbStreams = gbStreamMapper.selectAllByMediaServerId(mediaServerItem.getId());
             if (code == 0 ) {
                 if (dataStr != null) {
-                    streamPushItems = streamPushService.handleJSON(dataStr);
+                    streamPushItems = streamPushService.handleJSON(dataStr, mediaServerItem);
                 }
             }else {
                 logger.warn("鏇存柊瑙嗛娴佸け璐ワ紝閿欒code锛� " + code);
@@ -72,24 +74,27 @@
                     JSONObject jsonObject = new JSONObject();
                     jsonObject.put("app", streamPushItem.getApp());
                     jsonObject.put("stream", streamPushItem.getStream());
-                    subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_play,jsonObject,(response)->{
-                        updateMedia(response.getString("app"), response.getString("stream"));
-                    });
+                    jsonObject.put("mediaServerId", mediaServerItem.getId());
+                    subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_play,jsonObject,
+                            (IMediaServerItem mediaServerItemInuse, JSONObject response)->{
+                                updateMedia(mediaServerItem, response.getString("app"), response.getString("stream"));
+                            }
+                    );
                 }
             }
         }));
 
     }
 
-    public void addMedia(String app, String streamId) {
+    public void addMedia(IMediaServerItem mediaServerItem, String app, String streamId) {
         //浣跨敤寮傛鏇存柊鎺ㄦ祦
-        updateMedia(app, streamId);
+        updateMedia(mediaServerItem, app, streamId);
     }
 
 
-    public void updateMedia(String app, String streamId) {
+    public void updateMedia(IMediaServerItem mediaServerItem, String app, String streamId) {
         //浣跨敤寮傛鏇存柊鎺ㄦ祦
-        zlmresTfulUtils.getMediaList(app, streamId, "rtmp", json->{
+        zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId, "rtmp", json->{
 
             if (json == null) return;
             String dataStr = json.getString("data");
@@ -99,7 +104,7 @@
             List<StreamPushItem> streamPushItems = null;
             if (code == 0 ) {
                 if (dataStr != null) {
-                    streamPushItems = streamPushService.handleJSON(dataStr);
+                    streamPushItems = streamPushService.handleJSON(dataStr, mediaServerItem);
                 }
             }else {
                 logger.warn("鏇存柊瑙嗛娴佸け璐ワ紝閿欒code锛� " + code);
@@ -122,32 +127,32 @@
         }
     }
 
-    public void clearAllSessions() {
-        logger.info("娓呯┖鎵�鏈夊浗鏍囩浉鍏崇殑session");
-        JSONObject allSessionJSON = zlmresTfulUtils.getAllSession();
-        ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
-        HashSet<String> allLocalPorts = new HashSet();
-        if (allSessionJSON.getInteger("code") == 0) {
-            JSONArray data = allSessionJSON.getJSONArray("data");
-            if (data.size() > 0) {
-                for (int i = 0; i < data.size(); i++) {
-                    JSONObject sessionJOSN = data.getJSONObject(i);
-                    Integer local_port = sessionJOSN.getInteger("local_port");
-                    if (!local_port.equals(Integer.valueOf(mediaInfo.getHttpPort())) &&
-                        !local_port.equals(Integer.valueOf(mediaInfo.getHttpSSLport())) &&
-                        !local_port.equals(Integer.valueOf(mediaInfo.getRtmpPort())) &&
-                        !local_port.equals(Integer.valueOf(mediaInfo.getRtspPort())) &&
-                        !local_port.equals(Integer.valueOf(mediaInfo.getRtspSSlport())) &&
-                        !local_port.equals(Integer.valueOf(mediaInfo.getHookOnFlowReport()))){
-                        allLocalPorts.add(sessionJOSN.getInteger("local_port") + "");
-                     }
-                }
-            }
-        }
-        if (allLocalPorts.size() > 0) {
-            List<String> result = new ArrayList<>(allLocalPorts);
-            String localPortSStr = String.join(",", result);
-            zlmresTfulUtils.kickSessions(localPortSStr);
-        }
-    }
+//    public void clearAllSessions() {
+//        logger.info("娓呯┖鎵�鏈夊浗鏍囩浉鍏崇殑session");
+//        JSONObject allSessionJSON = zlmresTfulUtils.getAllSession();
+//        ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
+//        HashSet<String> allLocalPorts = new HashSet();
+//        if (allSessionJSON.getInteger("code") == 0) {
+//            JSONArray data = allSessionJSON.getJSONArray("data");
+//            if (data.size() > 0) {
+//                for (int i = 0; i < data.size(); i++) {
+//                    JSONObject sessionJOSN = data.getJSONObject(i);
+//                    Integer local_port = sessionJOSN.getInteger("local_port");
+//                    if (!local_port.equals(Integer.valueOf(mediaInfo.getHttpPort())) &&
+//                        !local_port.equals(Integer.valueOf(mediaInfo.getHttpSSLport())) &&
+//                        !local_port.equals(Integer.valueOf(mediaInfo.getRtmpPort())) &&
+//                        !local_port.equals(Integer.valueOf(mediaInfo.getRtspPort())) &&
+//                        !local_port.equals(Integer.valueOf(mediaInfo.getRtspSSlport())) &&
+//                        !local_port.equals(Integer.valueOf(mediaInfo.getHookOnFlowReport()))){
+//                        allLocalPorts.add(sessionJOSN.getInteger("local_port") + "");
+//                     }
+//                }
+//            }
+//        }
+//        if (allLocalPorts.size() > 0) {
+//            List<String> result = new ArrayList<>(allLocalPorts);
+//            String localPortSStr = String.join(",", result);
+//            zlmresTfulUtils.kickSessions(localPortSStr);
+//        }
+//    }
 }
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 8425d03..8e12e57 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -3,6 +3,8 @@
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.genersoft.iot.vmp.conf.MediaConfig;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import okhttp3.*;
 import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
@@ -21,23 +23,18 @@
 
     private final static Logger logger = LoggerFactory.getLogger(ZLMRESTfulUtils.class);
 
-    @Autowired
-    private MediaConfig mediaConfig;
-
-
-
     public interface RequestCallback{
         void run(JSONObject response);
     }
 
-    public JSONObject sendPost(String api, Map<String, Object> param, RequestCallback callback) {
+    public JSONObject sendPost(IMediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
         OkHttpClient client = new OkHttpClient();
-        String url = String.format("http://%s:%s/index/api/%s",  mediaConfig.getIp(), mediaConfig.getHttpPort(), api);
+        String url = String.format("http://%s:%s/index/api/%s",  mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
         JSONObject responseJSON = null;
         logger.debug(url);
 
         FormBody.Builder builder = new FormBody.Builder();
-        builder.add("secret",mediaConfig.getSecret());
+        builder.add("secret",mediaServerItem.getSecret());
         if (param != null && param.keySet().size() > 0) {
             for (String key : param.keySet()){
                 if (param.get(key) != null) {
@@ -96,14 +93,14 @@
     }
 
 
-    public void sendPostForImg(String api, Map<String, Object> param, String targetPath, String fileName) {
+    public void sendPostForImg(IMediaServerItem mediaServerItem, String api, Map<String, Object> param, String targetPath, String fileName) {
         OkHttpClient client = new OkHttpClient();
-        String url = String.format("http://%s:%s/index/api/%s",  mediaConfig.getIp(), mediaConfig.getHttpPort(), api);
+        String url = String.format("http://%s:%s/index/api/%s",  mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
         JSONObject responseJSON = null;
         logger.debug(url);
 
         FormBody.Builder builder = new FormBody.Builder();
-        builder.add("secret",mediaConfig.getSecret());
+        builder.add("secret",mediaServerItem.getSecret());
         if (param != null && param.keySet().size() > 0) {
             for (String key : param.keySet()){
                 if (param.get(key) != null) {
@@ -142,39 +139,39 @@
     }
 
 
-    public JSONObject getMediaList(String app, String stream, String schema, RequestCallback callback){
+    public JSONObject getMediaList(IMediaServerItem mediaServerItem,String app, String stream, String schema, RequestCallback callback){
         Map<String, Object> param = new HashMap<>();
         if (app != null) param.put("app",app);
         if (stream != null) param.put("stream",stream);
         if (schema != null) param.put("schema",schema);
         param.put("vhost","__defaultVhost__");
-        return sendPost("getMediaList",param, callback);
+        return sendPost(mediaServerItem, "getMediaList",param, callback);
     }
 
-    public JSONObject getMediaList(String app, String stream){
-        return getMediaList(app, stream,null,  null);
+    public JSONObject getMediaList(IMediaServerItem mediaServerItem,String app, String stream){
+        return getMediaList(mediaServerItem, app, stream,null,  null);
     }
 
-    public JSONObject getMediaList(RequestCallback callback){
-        return sendPost("getMediaList",null, callback);
+    public JSONObject getMediaList(IMediaServerItem mediaServerItem,RequestCallback callback){
+        return sendPost(mediaServerItem, "getMediaList",null, callback);
     }
 
-    public JSONObject getMediaInfo(String app, String schema, String stream){
+    public JSONObject getMediaInfo(IMediaServerItem mediaServerItem,String app, String schema, String stream){
         Map<String, Object> param = new HashMap<>();
         param.put("app",app);
         param.put("schema",schema);
         param.put("stream",stream);
         param.put("vhost","__defaultVhost__");
-        return sendPost("getMediaInfo",param, null);
+        return sendPost(mediaServerItem, "getMediaInfo",param, null);
     }
 
-    public JSONObject getRtpInfo(String stream_id){
+    public JSONObject getRtpInfo(IMediaServerItem mediaServerItem,String stream_id){
         Map<String, Object> param = new HashMap<>();
         param.put("stream_id",stream_id);
-        return sendPost("getRtpInfo",param, null);
+        return sendPost(mediaServerItem, "getRtpInfo",param, null);
     }
 
-    public JSONObject addFFmpegSource(String src_url, String dst_url, String timeout_ms,
+    public JSONObject addFFmpegSource(IMediaServerItem mediaServerItem,String src_url, String dst_url, String timeout_ms,
                                       boolean enable_hls, boolean enable_mp4, String ffmpeg_cmd_key){
         logger.info(src_url);
         logger.info(dst_url);
@@ -185,44 +182,44 @@
         param.put("enable_hls", enable_hls);
         param.put("enable_mp4", enable_mp4);
         param.put("ffmpeg_cmd_key", ffmpeg_cmd_key);
-        return sendPost("addFFmpegSource",param, null);
+        return sendPost(mediaServerItem, "addFFmpegSource",param, null);
     }
 
-    public JSONObject delFFmpegSource(String key){
+    public JSONObject delFFmpegSource(IMediaServerItem mediaServerItem,String key){
         Map<String, Object> param = new HashMap<>();
         param.put("key", key);
-        return sendPost("delFFmpegSource",param, null);
+        return sendPost(mediaServerItem, "delFFmpegSource",param, null);
     }
 
-    public JSONObject getMediaServerConfig(){
-        return sendPost("getServerConfig",null, null);
+    public JSONObject getMediaServerConfig(IMediaServerItem mediaServerItem){
+        return sendPost(mediaServerItem, "getServerConfig",null, null);
     }
 
-    public JSONObject setServerConfig(Map<String, Object> param){
-        return sendPost("setServerConfig",param, null);
+    public JSONObject setServerConfig(IMediaServerItem mediaServerItem, Map<String, Object> param){
+        return sendPost(mediaServerItem,"setServerConfig",param, null);
     }
 
-    public JSONObject openRtpServer(Map<String, Object> param){
-        return sendPost("openRtpServer",param, null);
+    public JSONObject openRtpServer(IMediaServerItem mediaServerItem,Map<String, Object> param){
+        return sendPost(mediaServerItem, "openRtpServer",param, null);
     }
 
-    public JSONObject closeRtpServer(Map<String, Object> param) {
-        return sendPost("closeRtpServer",param, null);
+    public JSONObject closeRtpServer(IMediaServerItem mediaServerItem,Map<String, Object> param) {
+        return sendPost(mediaServerItem, "closeRtpServer",param, null);
     }
 
-    public JSONObject listRtpServer() {
-        return sendPost("listRtpServer",null, null);
+    public JSONObject listRtpServer(IMediaServerItem mediaServerItem) {
+        return sendPost(mediaServerItem, "listRtpServer",null, null);
     }
 
-    public JSONObject startSendRtp(Map<String, Object> param) {
-        return sendPost("startSendRtp",param, null);
+    public JSONObject startSendRtp(IMediaServerItem mediaServerItem,Map<String, Object> param) {
+        return sendPost(mediaServerItem, "startSendRtp",param, null);
     }
 
-    public JSONObject stopSendRtp(Map<String, Object> param) {
-        return sendPost("stopSendRtp",param, null);
+    public JSONObject stopSendRtp(IMediaServerItem mediaServerItem,Map<String, Object> param) {
+        return sendPost(mediaServerItem, "stopSendRtp",param, null);
     }
 
-    public JSONObject addStreamProxy(String app, String stream, String url, boolean enable_hls, boolean enable_mp4, String rtp_type) {
+    public JSONObject addStreamProxy(IMediaServerItem mediaServerItem,String app, String stream, String url, boolean enable_hls, boolean enable_mp4, String rtp_type) {
         Map<String, Object> param = new HashMap<>();
         param.put("vhost", "__defaultVhost__");
         param.put("app", app);
@@ -231,33 +228,33 @@
         param.put("enable_hls", enable_hls?1:0);
         param.put("enable_mp4", enable_mp4?1:0);
         param.put("rtp_type", rtp_type);
-        return sendPost("addStreamProxy",param, null);
+        return sendPost(mediaServerItem, "addStreamProxy",param, null);
     }
 
-    public JSONObject closeStreams(String app, String stream) {
+    public JSONObject closeStreams(IMediaServerItem mediaServerItem,String app, String stream) {
         Map<String, Object> param = new HashMap<>();
         param.put("vhost", "__defaultVhost__");
         param.put("app", app);
         param.put("stream", stream);
         param.put("force", 1);
-        return sendPost("close_streams",param, null);
+        return sendPost(mediaServerItem, "close_streams",param, null);
     }
 
-    public JSONObject getAllSession() {
-        return sendPost("getAllSession",null, null);
+    public JSONObject getAllSession(IMediaServerItem mediaServerItem) {
+        return sendPost(mediaServerItem, "getAllSession",null, null);
     }
 
-    public void kickSessions(String localPortSStr) {
+    public void kickSessions(IMediaServerItem mediaServerItem, String localPortSStr) {
         Map<String, Object> param = new HashMap<>();
         param.put("local_port", localPortSStr);
-        sendPost("kick_sessions",param, null);
+        sendPost(mediaServerItem, "kick_sessions",param, null);
     }
 
-    public void getSnap(String flvUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
+    public void getSnap(IMediaServerItem mediaServerItem, String flvUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
         Map<String, Object> param = new HashMap<>();
         param.put("url", flvUrl);
         param.put("timeout_sec", timeout_sec);
         param.put("expire_sec", expire_sec);
-        sendPostForImg("getSnap",param, targetPath, fileName);
+        sendPostForImg(mediaServerItem, "getSnap",param, targetPath, fileName);
     }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
index ed069f8..5919c9f 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -5,6 +5,8 @@
 import com.genersoft.iot.vmp.conf.MediaConfig;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
 import com.genersoft.iot.vmp.gb28181.session.SsrcUtil;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -30,10 +32,10 @@
 
     private Map<String, Integer> currentStreams = null;
 
-    public int createRTPServer(String streamId) {
+    public int createRTPServer(IMediaServerItem mediaServerItem, String streamId) {
         if (currentStreams == null) {
             currentStreams = new HashMap<>();
-            JSONObject jsonObject = zlmresTfulUtils.listRtpServer();
+            JSONObject jsonObject = zlmresTfulUtils.listRtpServer(mediaServerItem);
             if (jsonObject != null) {
                 JSONArray data = jsonObject.getJSONArray("data");
                 if (data != null) {
@@ -48,7 +50,7 @@
         if (currentStreams.get(streamId) != null) {
             Map<String, Object> closeRtpServerParam = new HashMap<>();
             closeRtpServerParam.put("stream_id", streamId);
-            zlmresTfulUtils.closeRtpServer(closeRtpServerParam);
+            zlmresTfulUtils.closeRtpServer(mediaServerItem, closeRtpServerParam);
             currentStreams.remove(streamId);
         }
 
@@ -58,7 +60,7 @@
         param.put("port", newPort);
         param.put("enable_tcp", 1);
         param.put("stream_id", streamId);
-        JSONObject jsonObject = zlmresTfulUtils.openRtpServer(param);
+        JSONObject jsonObject = zlmresTfulUtils.openRtpServer(mediaServerItem, param);
 
         if (jsonObject != null) {
             switch (jsonObject.getInteger("code")){
@@ -68,11 +70,11 @@
                 case -300: // id宸茬粡瀛樺湪, 鍙兘宸茬粡鍦ㄥ叾浠栫鍙f帹娴�
                     Map<String, Object> closeRtpServerParam = new HashMap<>();
                     closeRtpServerParam.put("stream_id", streamId);
-                    zlmresTfulUtils.closeRtpServer(closeRtpServerParam);
+                    zlmresTfulUtils.closeRtpServer(mediaServerItem, closeRtpServerParam);
                     result = newPort;
                     break;
                 case -400: // 绔彛鍗犵敤
-                    result= createRTPServer(streamId);
+                    result= createRTPServer(mediaServerItem, streamId);
                     break;
                 default:
                     logger.error("鍒涘缓RTP Server 澶辫触 {}: " + jsonObject.getString("msg"), newPort);
@@ -85,20 +87,22 @@
         return result;
     }
 
-    public boolean closeRTPServer(String streamId) {
+    public boolean closeRTPServer(IMediaServerItem serverItem, String streamId) {
         boolean result = false;
-        Map<String, Object> param = new HashMap<>();
-        param.put("stream_id", streamId);
-        JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(param);
-        if (jsonObject != null ) {
-            if (jsonObject.getInteger("code") == 0) {
-                result = jsonObject.getInteger("hit") == 1;
+        if (serverItem !=null){
+            Map<String, Object> param = new HashMap<>();
+            param.put("stream_id", streamId);
+            JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(serverItem, param);
+            if (jsonObject != null ) {
+                if (jsonObject.getInteger("code") == 0) {
+                    result = jsonObject.getInteger("hit") == 1;
+                }else {
+                    logger.error("鍏抽棴RTP Server 澶辫触: " + jsonObject.getString("msg"));
+                }
             }else {
-                logger.error("鍏抽棴RTP Server 澶辫触: " + jsonObject.getString("msg"));
+                //  妫�鏌LM鐘舵��
+                logger.error("鍏抽棴RTP Server 澶辫触: 璇锋鏌LM鏈嶅姟");
             }
-        }else {
-            //  妫�鏌LM鐘舵��
-            logger.error("鍏抽棴RTP Server 澶辫触: 璇锋鏌LM鏈嶅姟");
         }
         return result;
     }
@@ -131,11 +135,11 @@
      * @param tcp 鏄惁涓簍cp
      * @return SendRtpItem
      */
-    public SendRtpItem createSendRtpItem(String ip, int port, String ssrc, String platformId, String deviceId, String channelId, boolean tcp){
+    public SendRtpItem createSendRtpItem(IMediaServerItem serverItem, String ip, int port, String ssrc, String platformId, String deviceId, String channelId, boolean tcp){
         String playSsrc = SsrcUtil.getPlaySsrc();
-        int localPort = createRTPServer(SsrcUtil.getPlaySsrc());
+        int localPort = createRTPServer(serverItem, SsrcUtil.getPlaySsrc());
         if (localPort != -1) {
-            closeRTPServer(playSsrc);
+            closeRTPServer(serverItem, playSsrc);
         }else {
             logger.error("娌℃湁鍙敤鐨勭鍙�");
             return null;
@@ -150,6 +154,7 @@
         sendRtpItem.setTcp(tcp);
         sendRtpItem.setApp("rtp");
         sendRtpItem.setLocalPort(localPort);
+        sendRtpItem.setMediaServerId(serverItem.getId());
         return sendRtpItem;
     }
 
@@ -163,11 +168,11 @@
      * @param tcp 鏄惁涓簍cp
      * @return SendRtpItem
      */
-    public SendRtpItem createSendRtpItem(String ip, int port, String ssrc, String platformId, String app, String stream, String channelId, boolean tcp){
+    public SendRtpItem createSendRtpItem(IMediaServerItem serverItem, String ip, int port, String ssrc, String platformId, String app, String stream, String channelId, boolean tcp){
         String playSsrc = SsrcUtil.getPlaySsrc();
-        int localPort = createRTPServer(SsrcUtil.getPlaySsrc());
+        int localPort = createRTPServer(serverItem, SsrcUtil.getPlaySsrc());
         if (localPort != -1) {
-            closeRTPServer(playSsrc);
+            closeRTPServer(serverItem, playSsrc);
         }else {
             logger.error("娌℃湁鍙敤鐨勭鍙�");
             return null;
@@ -182,21 +187,21 @@
         sendRtpItem.setChannelId(channelId);
         sendRtpItem.setTcp(tcp);
         sendRtpItem.setLocalPort(localPort);
+        sendRtpItem.setMediaServerId(serverItem.getId());
         return sendRtpItem;
     }
 
     /**
      * 璋冪敤zlm RESTful API 鈥斺�� startSendRtp
      */
-    public Boolean startSendRtpStream(Map<String, Object>param) {
+    public Boolean startSendRtpStream(IMediaServerItem mediaServerItem, Map<String, Object>param) {
         Boolean result = false;
-        JSONObject jsonObject = zlmresTfulUtils.startSendRtp(param);
-        logger.info(jsonObject.toJSONString());
+        JSONObject jsonObject = zlmresTfulUtils.startSendRtp(mediaServerItem, param);
         if (jsonObject == null) {
             logger.error("RTP鎺ㄦ祦澶辫触: 璇锋鏌LM鏈嶅姟");
         } else if (jsonObject.getInteger("code") == 0) {
             result= true;
-            logger.info("RTP鎺ㄦ祦璇锋眰鎴愬姛锛屾湰鍦版帹娴佺鍙o細" + jsonObject.getString("local_port"));
+            logger.info("RTP鎺ㄦ祦[ {}/{} ]璇锋眰鎴愬姛锛屾湰鍦版帹娴佺鍙o細{}" ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"));
         } else {
             logger.error("RTP鎺ㄦ祦澶辫触: " + jsonObject.getString("msg"));
         }
@@ -206,16 +211,16 @@
     /**
      * 鏌ヨ寰呰浆鎺ㄧ殑娴佹槸鍚﹀氨缁�
      */
-    public Boolean isRtpReady(String streamId) {
-        JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo("rtp", "rtmp", streamId);
+    public Boolean isRtpReady(MediaServerItem mediaServerItem, String streamId) {
+        JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtmp", streamId);
         return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
     }
 
     /**
      * 鏌ヨ寰呰浆鎺ㄧ殑娴佹槸鍚﹀氨缁�
      */
-    public Boolean isStreamReady(String app, String streamId) {
-        JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(app, "rtmp", streamId);
+    public Boolean isStreamReady(IMediaServerItem mediaServerItem, String app, String streamId) {
+        JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
         return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
     }
 
@@ -224,18 +229,17 @@
      * @param streamId
      * @return
      */
-    public int totalReaderCount(String app, String streamId) {
-        JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(app, "rtmp", streamId);
+    public int totalReaderCount(IMediaServerItem mediaServerItem, String app, String streamId) {
+        JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
         return mediaInfo.getInteger("totalReaderCount");
     }
 
     /**
      * 璋冪敤zlm RESTful API 鈥斺�� stopSendRtp
      */
-    public Boolean stopSendRtpStream(Map<String, Object>param) {
+    public Boolean stopSendRtpStream(IMediaServerItem mediaServerItem,Map<String, Object>param) {
         Boolean result = false;
-        JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(param);
-        logger.info(jsonObject.toJSONString());
+        JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param);
         if (jsonObject == null) {
             logger.error("鍋滄RTP鎺ㄦ祦澶辫触: 璇锋鏌LM鏈嶅姟");
         } else if (jsonObject.getInteger("code") == 0) {
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
index 956db14..d06c6c3 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
@@ -4,7 +4,10 @@
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.genersoft.iot.vmp.conf.MediaConfig;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+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 com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.service.IStreamProxyService;
 import org.slf4j.Logger;
@@ -14,10 +17,10 @@
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import javax.print.attribute.standard.Media;
+import java.util.*;
 
 @Component
 @Order(value=1)
@@ -25,140 +28,131 @@
 
     private final static Logger logger = LoggerFactory.getLogger(ZLMRunner.class);
 
-     @Autowired
-     private IVideoManagerStorager storager;
-
-    @Autowired
-    private MediaConfig mediaConfig;
-
-    @Value("${server.port}")
-    private String serverPort;
-
-    @Value("${server.ssl.enabled:false}")
-    private boolean sslEnabled;
-
-    private boolean startGetMedia = false;
+    private Map<String, Boolean> startGetMedia;
 
     @Autowired
     private ZLMRESTfulUtils zlmresTfulUtils;
 
     @Autowired
-    private ZLMMediaListManager zlmMediaListManager;
-
-    @Autowired
     private ZLMHttpHookSubscribe hookSubscribe;
-
-    @Autowired
-    private ZLMServerManger zlmServerManger;
 
     @Autowired
     private IStreamProxyService streamProxyService;
 
+    @Autowired
+    private IMediaServerService mediaServerService;
+
+    @Autowired
+    private MediaConfig mediaConfig;
+
     @Override
     public void run(String... strings) throws Exception {
-        // 璁㈤槄 zlm鍚姩浜嬩欢
-        hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,null,(response)->{
-            ZLMServerConfig ZLMServerConfig = JSONObject.toJavaObject(response, ZLMServerConfig.class);
-            zLmRunning(ZLMServerConfig);
+        IMediaServerItem presetMediaServer = mediaServerService.getOneByHostAndPort(
+                mediaConfig.getIp(), mediaConfig.getHttpPort());
+        if (presetMediaServer  != null) {
+            mediaConfig.setId(presetMediaServer.getId());
+            mediaServerService.update(mediaConfig);
+        }
+
+        // 璁㈤槄 zlm鍚姩浜嬩欢, 鏂扮殑zlm涔熶細浠庤繖閲岃繘鍏ョ郴缁�
+        hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,null,
+                (IMediaServerItem mediaServerItem, JSONObject response)->{
+            ZLMServerConfig zlmServerConfig = JSONObject.toJavaObject(response, ZLMServerConfig.class);
+            if (zlmServerConfig !=null ) {
+                startGetMedia.remove(zlmServerConfig.getGeneralMediaServerId());
+                mediaServerService.handLeZLMServerConfig(zlmServerConfig);
+//                zLmRunning(zlmServerConfig);
+            }
         });
 
         // 鑾峰彇zlm淇℃伅
-        logger.info("绛夊緟zlm鎺ュ叆...");
-        startGetMedia = true;
-        ZLMServerConfig ZLMServerConfig = getMediaServerConfig();
+        logger.info("绛夊緟榛樿zlm鎺ュ叆...");
 
-        if (ZLMServerConfig != null) {
-            zLmRunning(ZLMServerConfig);
+        // 鑾峰彇鎵�鏈夌殑zlm锛� 骞跺紑鍚富鍔ㄨ繛鎺�
+        List<IMediaServerItem> all = mediaServerService.getAll();
+        if (presetMediaServer == null) {
+            all.add(mediaConfig.getMediaSerItem());
         }
+        for (IMediaServerItem mediaServerItem : all) {
+            if (startGetMedia == null) startGetMedia = new HashMap<>();
+            startGetMedia.put(mediaServerItem.getId(), true);
+            new Thread(() -> {
+                ZLMServerConfig zlmServerConfig = getMediaServerConfig(mediaServerItem);
+                if (zlmServerConfig != null) {
+                    startGetMedia.remove(mediaServerItem.getId());
+                    mediaServerService.handLeZLMServerConfig(zlmServerConfig);
+                }
+            }).start();
+        }
+        Timer timer = new Timer();
+        // 1鍒嗛挓鍚庢湭杩炴帴鍒板垯涓嶅啀鍘讳富鍔ㄨ繛鎺�
+        timer.schedule(new TimerTask() {
+            @Override
+            public void run() {
+            if (startGetMedia != null) {
+                Set<String> allZlmId = startGetMedia.keySet();
+                for (String id : allZlmId) {
+                    logger.error("[ {} ]]涓诲姩杩炴帴澶辫触锛屼笉鍐嶄富鍔ㄨ繛鎺�", id);
+                    startGetMedia.put(id, false);
+                }
+            }
+            }
+        }, 60 * 1000 * 2);
     }
 
-    public ZLMServerConfig getMediaServerConfig() {
-        if (!startGetMedia) return null;
-        JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig();
+    public ZLMServerConfig getMediaServerConfig(IMediaServerItem mediaServerItem) {
+        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);
-
+                ZLMServerConfig.setIp(mediaServerItem.getIp());
             }
         } else {
-            logger.error("getMediaServerConfig澶辫触, 1s鍚庨噸璇�");
+            logger.error("[ {} ]-[ {}:{} ]涓诲姩杩炴帴澶辫触澶辫触, 2s鍚庨噸璇�",
+                    mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
             try {
-                Thread.sleep(1000);
+                Thread.sleep(2000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
-            ZLMServerConfig = getMediaServerConfig();
+            ZLMServerConfig = getMediaServerConfig(mediaServerItem);
         }
         return ZLMServerConfig;
-    }
 
-    private void saveZLMConfig() {
-        logger.info("璁剧疆zlm...");
-        String protocol = sslEnabled ? "https" : "http";
-        String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaConfig.getHookIp(), serverPort);
-        String recordHookPrex = null;
-        if (mediaConfig.getRecordAssistPort() != 0) {
-            recordHookPrex = String.format("http://127.0.0.1:%s/api/record", mediaConfig.getRecordAssistPort());
-        }
-        Map<String, Object> param = new HashMap<>();
-        param.put("api.secret",mediaConfig.getSecret()); // -profile:v Baseline
-        param.put("ffmpeg.cmd","%s -fflags nobuffer -rtsp_transport tcp -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264  -f flv %s");
-        param.put("hook.enable","1");
-        param.put("hook.on_flow_report","");
-        param.put("hook.on_play",String.format("%s/on_play", hookPrex));
-        param.put("hook.on_http_access","");
-        param.put("hook.on_publish", String.format("%s/on_publish", hookPrex));
-        param.put("hook.on_record_mp4",recordHookPrex != null? String.format("%s/on_record_mp4", recordHookPrex): "");
-        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", hookPrex));
-        param.put("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex));
-        param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrex));
-        param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
-        param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
-        param.put("hook.timeoutSec","20");
-        param.put("general.streamNoneReaderDelayMS",mediaConfig.getStreamNoneReaderDelayMS());
-
-        JSONObject responseJSON = zlmresTfulUtils.setServerConfig(param);
-
-        if (responseJSON != null && responseJSON.getInteger("code") == 0) {
-            logger.info("璁剧疆zlm鎴愬姛");
-        }else {
-            logger.info("璁剧疆zlm澶辫触");
-        }
     }
 
     /**
      * zlm 杩炴帴鎴愬姛鎴栬�厇lm閲嶅惎鍚�
      */
-    private void zLmRunning(ZLMServerConfig zlmServerConfig){
-        logger.info( "[ id: " + zlmServerConfig.getGeneralMediaServerId() + "] zlm鎺ュ叆鎴愬姛...");
-        // 鍏抽棴寰幆鑾峰彇zlm閰嶇疆
-        startGetMedia = false;
-        if (mediaConfig.isAutoConfig()) saveZLMConfig();
-        zlmServerManger.updateServerCatch(zlmServerConfig);
-
-        // 娓呯┖鎵�鏈塻ession
-//        zlmMediaListManager.clearAllSessions();
-
-        // 鏇存柊娴佸垪琛�
-        zlmMediaListManager.updateMediaList();
-        // 鎭㈠娴佷唬鐞�
-        List<StreamProxyItem> streamProxyListForEnable = storager.getStreamProxyListForEnable(true);
-        for (StreamProxyItem streamProxyDto : streamProxyListForEnable) {
-            logger.info("鎭㈠娴佷唬鐞嗭紝" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
-            JSONObject jsonObject = streamProxyService.addStreamProxyToZlm(streamProxyDto);
-            if (jsonObject == null) {
-                // 璁剧疆涓烘湭鍚敤
-                logger.info("鎭㈠娴佷唬鐞嗗け璐ワ紝璇锋鏌ユ祦鍦板潃鍚庨噸鏂板惎鐢�" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
-                streamProxyService.stop(streamProxyDto.getApp(), streamProxyDto.getStream());
-            }else if (jsonObject.getInteger("code") != 0){ // TODO 灏嗛敊璇俊鎭瓨鍏ユ暟鎹簱锛� 鍓嶇灞曠ず
-                logger.info("鎭㈠娴佷唬鐞嗗け璐ワ細" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream() + "[ " + JSONObject.toJSONString(jsonObject) + " ]");
-                streamProxyService.stop(streamProxyDto.getApp(), streamProxyDto.getStream());
-            }
-        }
-    }
+//    private void zLmRunning(ZLMServerConfig zlmServerConfig){
+//        logger.info( "[ id: " + zlmServerConfig.getGeneralMediaServerId() + "] zlm鎺ュ叆鎴愬姛...");
+//        // 鍏抽棴寰幆鑾峰彇zlm閰嶇疆
+//        startGetMedia = false;
+//        MediaServerItem mediaServerItem = new MediaServerItem(zlmServerConfig, sipIp);
+//        storager.updateMediaServer(mediaServerItem);
+//
+//        if (mediaServerItem.isAutoConfig()) setZLMConfig(mediaServerItem);
+//        zlmServerManger.updateServerCatchFromHook(zlmServerConfig);
+//
+//        // 娓呯┖鎵�鏈塻ession
+////        zlmMediaListManager.clearAllSessions();
+//
+//        // 鏇存柊娴佸垪琛�
+//        zlmMediaListManager.updateMediaList(mediaServerItem);
+//        // 鎭㈠娴佷唬鐞�, 鍙煡鎵捐繖涓繖涓祦濯掍綋
+//        List<StreamProxyItem> streamProxyListForEnable = storager.getStreamProxyListForEnableInMediaServer(
+//                mediaServerItem.getId(), true);
+//        for (StreamProxyItem streamProxyDto : streamProxyListForEnable) {
+//            logger.info("鎭㈠娴佷唬鐞嗭紝" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
+//            JSONObject jsonObject = streamProxyService.addStreamProxyToZlm(streamProxyDto);
+//            if (jsonObject == null) {
+//                // 璁剧疆涓烘湭鍚敤
+//                logger.info("鎭㈠娴佷唬鐞嗗け璐ワ紝璇锋鏌ユ祦鍦板潃鍚庨噸鏂板惎鐢�" + streamProxyDto.getApp() + "/" + streamProxyDto.getStream());
+//                streamProxyService.stop(streamProxyDto.getApp(), streamProxyDto.getStream());
+//            }
+//        }
+//    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
index 21fcebf..c1a9bd2 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
@@ -34,11 +34,14 @@
     @JSONField(name = "general.streamNoneReaderDelayMS")
     private String generalStreamNoneReaderDelayMS;
 
+    @JSONField(name = "ip")
     private String ip;
 
     private String sdpIp;
 
     private String streamIp;
+
+    private String hookIp;
 
     private String updateTime;
 
@@ -66,7 +69,7 @@
     private String hookEnable;
 
     @JSONField(name = "hook.on_flow_report")
-    private Integer hookOnFlowReport;
+    private String hookOnFlowReport;
 
     @JSONField(name = "hook.on_http_access")
     private String hookOnHttpAccess;
@@ -117,7 +120,7 @@
     private String httpNotFound;
 
     @JSONField(name = "http.port")
-    private Integer httpPort;
+    private int httpPort;
 
     @JSONField(name = "http.rootPath")
     private String httpRootPath;
@@ -126,7 +129,7 @@
     private String httpSendBufSize;
 
     @JSONField(name = "http.sslport")
-    private Integer httpSSLport;
+    private int httpSSLport;
 
     @JSONField(name = "multicast.addrMax")
     private String multicastAddrMax;
@@ -159,10 +162,10 @@
     private String rtmpModifyStamp;
 
     @JSONField(name = "rtmp.port")
-    private Integer rtmpPort;
+    private int rtmpPort;
 
     @JSONField(name = "rtmp.sslport")
-    private Integer rtmpSslPort;
+    private int rtmpSslPort;
 
     @JSONField(name = "rtp.audioMtuSize")
     private String rtpAudioMtuSize;
@@ -186,7 +189,7 @@
     private String rtpProxyDumpDir;
 
     @JSONField(name = "rtp_proxy.port")
-    private Integer rtpProxyPort;
+    private int rtpProxyPort;
 
     @JSONField(name = "rtp_proxy.timeoutSec")
     private String rtpProxyTimeoutSec;
@@ -201,16 +204,25 @@
     private String rtspKeepAliveSecond;
 
     @JSONField(name = "rtsp.port")
-    private Integer rtspPort;
+    private int rtspPort;
 
     @JSONField(name = "rtsp.sslport")
-    private Integer rtspSSlport;
+    private int rtspSSlport;
 
     @JSONField(name = "shell.maxReqSize")
     private String shellMaxReqSize;
 
     @JSONField(name = "shell.shell")
     private String shellPhell;
+
+
+    public String getHookIp() {
+        return hookIp;
+    }
+
+    public void setHookIp(String hookIp) {
+        this.hookIp = hookIp;
+    }
 
     public String getApiDebug() {
         return apiDebug;
@@ -388,11 +400,11 @@
         this.hookEnable = hookEnable;
     }
 
-    public Integer getHookOnFlowReport() {
+    public String getHookOnFlowReport() {
         return hookOnFlowReport;
     }
 
-    public void setHookOnFlowReport(Integer hookOnFlowReport) {
+    public void setHookOnFlowReport(String hookOnFlowReport) {
         this.hookOnFlowReport = hookOnFlowReport;
     }
 
@@ -524,11 +536,11 @@
         this.httpNotFound = httpNotFound;
     }
 
-    public Integer getHttpPort() {
+    public int getHttpPort() {
         return httpPort;
     }
 
-    public void setHttpPort(Integer httpPort) {
+    public void setHttpPort(int httpPort) {
         this.httpPort = httpPort;
     }
 
@@ -548,11 +560,11 @@
         this.httpSendBufSize = httpSendBufSize;
     }
 
-    public Integer getHttpSSLport() {
+    public int getHttpSSLport() {
         return httpSSLport;
     }
 
-    public void setHttpSSLport(Integer httpSSLport) {
+    public void setHttpSSLport(int httpSSLport) {
         this.httpSSLport = httpSSLport;
     }
 
@@ -636,19 +648,19 @@
         this.rtmpModifyStamp = rtmpModifyStamp;
     }
 
-    public Integer getRtmpPort() {
+    public int getRtmpPort() {
         return rtmpPort;
     }
 
-    public void setRtmpPort(Integer rtmpPort) {
+    public void setRtmpPort(int rtmpPort) {
         this.rtmpPort = rtmpPort;
     }
 
-    public Integer getRtmpSslPort() {
+    public int getRtmpSslPort() {
         return rtmpSslPort;
     }
 
-    public void setRtmpSslPort(Integer rtmpSslPort) {
+    public void setRtmpSslPort(int rtmpSslPort) {
         this.rtmpSslPort = rtmpSslPort;
     }
 
@@ -708,11 +720,11 @@
         this.rtpProxyDumpDir = rtpProxyDumpDir;
     }
 
-    public Integer getRtpProxyPort() {
+    public int getRtpProxyPort() {
         return rtpProxyPort;
     }
 
-    public void setRtpProxyPort(Integer rtpProxyPort) {
+    public void setRtpProxyPort(int rtpProxyPort) {
         this.rtpProxyPort = rtpProxyPort;
     }
 
@@ -748,19 +760,19 @@
         this.rtspKeepAliveSecond = rtspKeepAliveSecond;
     }
 
-    public Integer getRtspPort() {
+    public int getRtspPort() {
         return rtspPort;
     }
 
-    public void setRtspPort(Integer rtspPort) {
+    public void setRtspPort(int rtspPort) {
         this.rtspPort = rtspPort;
     }
 
-    public Integer getRtspSSlport() {
+    public int getRtspSSlport() {
         return rtspSSlport;
     }
 
-    public void setRtspSSlport(Integer rtspSSlport) {
+    public void setRtspSSlport(int rtspSSlport) {
         this.rtspSSlport = rtspSSlport;
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerManger.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerManger.java
deleted file mode 100644
index fde3b44..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerManger.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm;
-
-import com.genersoft.iot.vmp.conf.MediaConfig;
-import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-@Component
-public class ZLMServerManger {
-
-    @Autowired
-    private IRedisCatchStorage redisCatchStorage;
-
-    @Autowired
-    private MediaConfig mediaConfig;
-
-    public void updateServerCatch(ZLMServerConfig zlmServerConfig) {
-
-        zlmServerConfig.setIp(mediaConfig.getIp());
-        zlmServerConfig.setStreamIp(mediaConfig.getStreamIp());
-        zlmServerConfig.setSdpIp(mediaConfig.getSdpIp());
-        zlmServerConfig.setHttpPort(mediaConfig.getHttpPort());
-
-        if(!StringUtils.isEmpty(mediaConfig.getHttpSSlPort()))
-            zlmServerConfig.setHttpSSLport(mediaConfig.getHttpSSlPort());
-
-        if(!StringUtils.isEmpty(mediaConfig.getRtspPort()))
-            zlmServerConfig.setRtspPort(mediaConfig.getRtspPort());
-
-        if(!StringUtils.isEmpty(mediaConfig.getRtspSSLPort()))
-            zlmServerConfig.setRtspSSlport(mediaConfig.getRtspSSLPort());
-
-        if(!StringUtils.isEmpty(mediaConfig.getRtmpPort()))
-            zlmServerConfig.setRtmpPort(mediaConfig.getRtmpPort());
-
-        if(!StringUtils.isEmpty(mediaConfig.getRtmpSSlPort()))
-            zlmServerConfig.setRtmpSslPort(mediaConfig.getRtmpSSlPort());
-
-        if(!StringUtils.isEmpty(mediaConfig.getRtpProxyPort()))
-            zlmServerConfig.setRtpProxyPort(mediaConfig.getRtpProxyPort());
-
-        redisCatchStorage.updateMediaInfo(zlmServerConfig);
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IMediaServerItem.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IMediaServerItem.java
new file mode 100644
index 0000000..6497162
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IMediaServerItem.java
@@ -0,0 +1,92 @@
+package com.genersoft.iot.vmp.media.zlm.dto;
+
+public interface IMediaServerItem {
+
+    String getId();
+
+    void setId(String id);
+
+    String getIp();
+
+    void setIp(String ip);
+
+    String getHookIp();
+
+    void setHookIp(String hookIp);
+
+    String getSdpIp();
+
+    void setSdpIp(String sdpIp);
+
+    String getStreamIp();
+
+    void setStreamIp(String streamIp);
+
+    int getHttpPort();
+
+    void setHttpPort(int httpPort);
+
+    int getHttpSSlPort();
+
+    void setHttpSSlPort(int httpSSlPort);
+
+    int getRtmpPort();
+
+    void setRtmpPort(int rtmpPort);
+
+    int getRtmpSSlPort();
+
+    void setRtmpSSlPort(int rtmpSSlPort);
+
+    int getRtpProxyPort();
+
+    void setRtpProxyPort(int rtpProxyPort);
+
+    int getRtspPort();
+
+    void setRtspPort(int rtspPort);
+
+    int getRtspSSLPort();
+
+    void setRtspSSLPort(int rtspSSLPort);
+
+    boolean isAutoConfig();
+
+    void setAutoConfig(boolean autoConfig);
+
+    String getSecret();
+
+    void setSecret(String secret);
+
+    String getStreamNoneReaderDelayMS();
+
+    void setStreamNoneReaderDelayMS(String streamNoneReaderDelayMS);
+
+    boolean isRtpEnable();
+
+    void setRtpEnable(boolean rtpEnable);
+
+    String getRtpPortRange();
+
+    void setRtpPortRange(String rtpPortRange);
+
+    int getRecordAssistPort();
+
+    void setRecordAssistPort(int recordAssistPort);
+
+    boolean isDocker();
+
+    void setDocker(boolean docker);
+
+    String getUpdateTime();
+
+    void setUpdateTime(String updateTime);
+
+    String getCreateTime();
+
+    void setCreateTime(String createTime);
+
+    int getCount();
+
+    void setCount(int count);
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaItem.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaItem.java
index 24bfcc1..6d9ceee 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaItem.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaItem.java
@@ -78,6 +78,10 @@
      */
     private String vhost;
 
+    /**
+     * 鏄惁鏄痙ocker閮ㄧ讲锛� docker閮ㄧ讲涓嶄細鑷姩鏇存柊zlm浣跨敤鐨勭鍙o紝闇�瑕佽嚜宸辨墜鍔ㄤ慨鏀�
+     */
+    private boolean docker;
 
     public static class MediaTrack {
         /**
@@ -364,4 +368,12 @@
     public OriginSock getOriginSock() {
         return originSock;
     }
+
+    public boolean isDocker() {
+        return docker;
+    }
+
+    public void setDocker(boolean docker) {
+        this.docker = docker;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
new file mode 100644
index 0000000..b56881f
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
@@ -0,0 +1,254 @@
+package com.genersoft.iot.vmp.media.zlm.dto;
+
+
+import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
+import org.springframework.util.StringUtils;
+
+public class MediaServerItem implements IMediaServerItem{
+
+    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 boolean autoConfig;
+
+    private String secret;
+
+    private String streamNoneReaderDelayMS;
+
+    private boolean rtpEnable;
+
+    private String rtpPortRange;
+
+    private int recordAssistPort;
+
+    private String createTime;
+
+    private String updateTime;
+
+    private boolean docker;
+
+    private int count;
+
+    public MediaServerItem() {
+    }
+
+    public MediaServerItem(ZLMServerConfig zlmServerConfig, String sipIp) {
+        id = zlmServerConfig.getGeneralMediaServerId();
+        ip = zlmServerConfig.getIp();
+        hookIp = StringUtils.isEmpty(zlmServerConfig.getHookIp())? sipIp: zlmServerConfig.getHookIp();
+        sdpIp = StringUtils.isEmpty(zlmServerConfig.getSdpIp())? zlmServerConfig.getIp(): zlmServerConfig.getSdpIp();
+        streamIp = StringUtils.isEmpty(zlmServerConfig.getStreamIp())? zlmServerConfig.getIp(): zlmServerConfig.getStreamIp();
+        httpPort = zlmServerConfig.getHttpPort();
+        httpSSlPort = zlmServerConfig.getHttpSSLport();
+        rtmpPort = zlmServerConfig.getRtmpPort();
+        rtmpSSlPort = zlmServerConfig.getRtmpSslPort();
+        rtpProxyPort = zlmServerConfig.getRtpProxyPort();
+        rtspPort = zlmServerConfig.getRtspPort();
+        rtspSSLPort = zlmServerConfig.getRtspSSlport();
+        autoConfig = true; // 榛樿鍊紅rue;
+        secret = zlmServerConfig.getApiSecret();
+        streamNoneReaderDelayMS = zlmServerConfig.getGeneralStreamNoneReaderDelayMS();
+        rtpEnable = false; // 榛樿浣跨敤鍗曠鍙�;鐩村埌鐢ㄦ埛鑷繁璁剧疆寮�鍚绔彛
+        recordAssistPort = 0; // 榛樿鍏抽棴
+
+    }
+
+    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 boolean isAutoConfig() {
+        return autoConfig;
+    }
+
+    public void setAutoConfig(boolean autoConfig) {
+        this.autoConfig = autoConfig;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+
+    public void setSecret(String secret) {
+        this.secret = secret;
+    }
+
+    public String getStreamNoneReaderDelayMS() {
+        return streamNoneReaderDelayMS;
+    }
+
+    public void setStreamNoneReaderDelayMS(String streamNoneReaderDelayMS) {
+        this.streamNoneReaderDelayMS = streamNoneReaderDelayMS;
+    }
+
+    public boolean isRtpEnable() {
+        return rtpEnable;
+    }
+
+    public void setRtpEnable(boolean rtpEnable) {
+        this.rtpEnable = rtpEnable;
+    }
+
+    public String getRtpPortRange() {
+        return rtpPortRange;
+    }
+
+    public void setRtpPortRange(String rtpPortRange) {
+        this.rtpPortRange = rtpPortRange;
+    }
+
+    public int getRecordAssistPort() {
+        return recordAssistPort;
+    }
+
+    public void setRecordAssistPort(int recordAssistPort) {
+        this.recordAssistPort = recordAssistPort;
+    }
+
+    @Override
+    public boolean isDocker() {
+        return docker;
+    }
+
+    @Override
+    public void setDocker(boolean docker) {
+        this.docker = docker;
+    }
+
+    public String getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(String createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(String updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public int getCount() {
+        return count;
+    }
+
+    public void setCount(int count) {
+        this.count = count;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
index 3f997a6..40ba215 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
@@ -7,6 +7,7 @@
     private String type;
     private String app;
     private String stream;
+    private String mediaServerId;
     private String url;
     private String src_url;
     private String dst_url;
@@ -17,6 +18,7 @@
     private boolean enable_hls;
     private boolean enable_mp4;
     private String platformGbId;
+    private String createTime;
 
     public String getType() {
         return type;
@@ -40,6 +42,16 @@
 
     public void setStream(String stream) {
         this.stream = stream;
+    }
+
+    @Override
+    public String getMediaServerId() {
+        return mediaServerId;
+    }
+
+    @Override
+    public void setMediaServerId(String mediaServerId) {
+        this.mediaServerId = mediaServerId;
     }
 
     public String getUrl() {
@@ -122,4 +134,12 @@
     public void setPlatformGbId(String platformGbId) {
         this.platformGbId = platformGbId;
     }
+
+    public String getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(String createTime) {
+        this.createTime = createTime;
+    }
 }
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 7a1c49b..73e162a 100644
--- 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
@@ -76,6 +76,11 @@
      */
     private String vhost;
 
+    /**
+     * 浣跨敤鐨勬祦濯掍綋ID
+     */
+    private String mediaServerId;
+
     public String getVhost() {
         return vhost;
     }
@@ -202,5 +207,14 @@
     }
 
 
+    @Override
+    public String getMediaServerId() {
+        return mediaServerId;
+    }
+
+    @Override
+    public void setMediaServerId(String mediaServerId) {
+        this.mediaServerId = mediaServerId;
+    }
 }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMRunInfo.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMRunInfo.java
new file mode 100644
index 0000000..624e4e1
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMRunInfo.java
@@ -0,0 +1,33 @@
+package com.genersoft.iot.vmp.media.zlm.dto;
+
+/**
+ * 璁板綍zlm杩愯涓竴浜涘弬鏁�
+ */
+public class ZLMRunInfo {
+
+    /**
+     * zlm褰撳墠娴佹暟閲�
+     */
+    private int mediaCount;
+
+    /**
+     * 鍦ㄧ嚎鐘舵��
+     */
+    private boolean online;
+
+    public int getMediaCount() {
+        return mediaCount;
+    }
+
+    public void setMediaCount(int mediaCount) {
+        this.mediaCount = mediaCount;
+    }
+
+    public boolean isOnline() {
+        return online;
+    }
+
+    public void setOnline(boolean online) {
+        this.online = online;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
new file mode 100644
index 0000000..7a57bed
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
@@ -0,0 +1,44 @@
+package com.genersoft.iot.vmp.service;
+
+import com.genersoft.iot.vmp.conf.MediaConfig;
+import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+
+import java.util.List;
+
+/**
+ * 濯掍綋鏈嶅姟鑺傜偣
+ */
+public interface IMediaServerService {
+
+    List<IMediaServerItem> getAll();
+
+    IMediaServerItem getOne(String generalMediaServerId);
+
+    IMediaServerItem getOneByHostAndPort(String host, int port);
+
+    /**
+     * 鏂扮殑鑺傜偣鍔犲叆
+     * @param zlmServerConfig
+     * @return
+     */
+    void handLeZLMServerConfig(ZLMServerConfig zlmServerConfig);
+
+    void updateServerCatch(IMediaServerItem mediaServerItem, Integer count, Boolean b);
+
+    IMediaServerItem getMediaServerForMinimumLoad();
+
+    void setZLMConfig(IMediaServerItem mediaServerItem);
+
+    void init();
+
+    void closeRTPServer(Device device, String channelId);
+
+    void update(MediaConfig mediaConfig);
+
+    void addCount(String mediaServerId);
+
+    void removeCount(String mediaServerId);
+}
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 010870a..868a831 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/IMediaService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IMediaService.java
@@ -2,6 +2,8 @@
 
 import com.alibaba.fastjson.JSONArray;
 import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 
 /**
  * 濯掍綋淇℃伅涓氬姟
@@ -14,23 +16,8 @@
      * @param stream
      * @return
      */
-    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream);
+    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId,String addr);
 
-    /**
-     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 鍙槸鍦板潃鎷兼帴
-     * @param app
-     * @param stream
-     * @return
-     */
-    StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks);
-
-    /**
-     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 鍙槸鍦板潃鎷兼帴锛岃繑鍥炵殑ip浣跨敤杩滅▼璁块棶ip锛岄�傜敤涓巣lm涓巜vp鍦ㄤ竴鍙颁富鏈虹殑鎯呭喌
-     * @param app
-     * @param stream
-     * @return
-     */
-    StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks, String addr);
 
     /**
      * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 閫氳繃zlm鎺ュ彛妫�鏌ユ槸鍚﹀瓨鍦�, 杩斿洖鐨刬p浣跨敤杩滅▼璁块棶ip锛岄�傜敤涓巣lm涓巜vp鍦ㄤ竴鍙颁富鏈虹殑鎯呭喌
@@ -38,5 +25,21 @@
      * @param stream
      * @return
      */
-    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String addr);
+    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId);
+
+    /**
+     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 鍙槸鍦板潃鎷兼帴
+     * @param app
+     * @param stream
+     * @return
+     */
+    StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaServerItem, String app, String stream, JSONArray tracks);
+
+    /**
+     * 鏍规嵁搴旂敤鍚嶅拰娴両D鑾峰彇鎾斁鍦板潃, 鍙槸鍦板潃鎷兼帴锛岃繑鍥炵殑ip浣跨敤杩滅▼璁块棶ip锛岄�傜敤涓巣lm涓巜vp鍦ㄤ竴鍙颁富鏈虹殑鎯呭喌
+     * @param app
+     * @param stream
+     * @return
+     */
+    StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks, String addr);
 }
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 a649267..fdc86d6 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -1,8 +1,11 @@
 package com.genersoft.iot.vmp.service;
 
 import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
 
 /**
@@ -10,8 +13,10 @@
  */
 public interface IPlayService {
 
-    void onPublishHandlerForPlayBack(JSONObject resonse, String deviceId, String channelId, String uuid);
-    void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, String uuid);
+    void onPublishHandlerForPlayBack(IMediaServerItem mediaServerItem,JSONObject resonse, String deviceId, String channelId, String uuid);
+    void onPublishHandlerForPlay(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid);
 
-    PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
+    PlayResult play(IMediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
+
+    IMediaServerItem getNewMediaServerItem(Device device);
 }
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 2f7388a..fa79d69 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
@@ -1,6 +1,8 @@
 package com.genersoft.iot.vmp.service;
 
 import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
 import com.github.pagehelper.PageInfo;
 
@@ -61,5 +63,5 @@
      * 鑾峰彇ffmpeg.cmd妯℃澘
      * @return
      */
-    JSONObject getFFmpegCMDs();
+    JSONObject getFFmpegCMDs(IMediaServerItem mediaServerItem);
 }
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 e66480a..eaf2490 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.service;
 
 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.github.pagehelper.PageInfo;
 
@@ -8,7 +9,7 @@
 
 public interface IStreamPushService {
 
-    List<StreamPushItem> handleJSON(String json);
+    List<StreamPushItem> handleJSON(String json, IMediaServerItem mediaServerItem);
 
     /**
      * 灏嗗簲鐢ㄥ悕鍜屾祦ID鍔犲叆鍥芥爣鍏宠仈
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
new file mode 100644
index 0000000..a90225a
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -0,0 +1,340 @@
+package com.genersoft.iot.vmp.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.conf.MediaConfig;
+import com.genersoft.iot.vmp.conf.ProxyServletConfig;
+import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
+import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
+import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.ZLMRunInfo;
+import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
+import com.genersoft.iot.vmp.storager.dao.MediaServerMapper;
+import org.mitre.dsmiley.httpproxy.ProxyServlet;
+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 java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * 濯掍綋鏈嶅姟鍣ㄨ妭鐐圭鐞�
+ */
+@Service
+public class MediaServerServiceImpl implements IMediaServerService {
+
+    private final static Logger logger = LoggerFactory.getLogger(MediaServerServiceImpl.class);
+
+    private Map<String, IMediaServerItem> zlmServers = new HashMap<>(); // 鎵�鏈夋暟鎹簱鐨剒lm鐨勭紦瀛�
+    private Map<String, Integer> zlmServerStatus = new LinkedHashMap<>(); // 鎵�鏈変笂绾跨殑zlm鐨勭紦瀛樹互鍙婅礋杞�
+
+    @Value("${sip.ip}")
+    private String sipIp;
+
+    @Value("${server.ssl.enabled:false}")
+    private boolean sslEnabled;
+
+    @Value("${server.port}")
+    private String serverPort;
+
+    @Autowired
+    private MediaConfig mediaConfig;
+
+    @Autowired
+    private ZLMRESTfulUtils zlmresTfulUtils;
+
+    @Autowired
+    private MediaServerMapper mediaServerMapper;
+
+
+    @Autowired
+    private IRedisCatchStorage redisCatchStorage;
+
+    @Autowired
+    private VideoStreamSessionManager streamSession;
+
+    @Autowired
+    private ZLMRTPServerFactory zlmrtpServerFactory;
+
+    private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+    /**
+     * 鍒濆鍖�
+     */
+    @Override
+    public void init() {
+        zlmServers.clear();
+        zlmServerStatus.clear();
+        List<MediaServerItem> mediaServerItemList = mediaServerMapper.queryAll();
+        for (IMediaServerItem mediaServerItem : mediaServerItemList) {
+            zlmServers.put(mediaServerItem.getId(), mediaServerItem);
+        }
+    }
+
+    @Override
+    public void closeRTPServer(Device device, String channelId) {
+        StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
+        IMediaServerItem mediaServerItem = null;
+        if (streamInfo != null) {
+            mediaServerItem = this.getOne (streamInfo.getMediaServerId());
+        }
+        String streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
+        zlmrtpServerFactory.closeRTPServer(mediaServerItem, streamId);
+        streamSession.remove(device.getDeviceId(), channelId);
+    }
+
+    @Override
+    public void update(MediaConfig mediaConfig) {
+
+    }
+
+    @Override
+    public List<IMediaServerItem> getAll() {
+        if (zlmServers.size() == 0) {
+            init();
+        }
+        List<IMediaServerItem> result = new ArrayList<>();
+        for (String id : zlmServers.keySet()) {
+            IMediaServerItem mediaServerItem = zlmServers.get(id);
+            mediaServerItem.setCount(zlmServerStatus.get(id) == null ? 0 : zlmServerStatus.get(id));
+            result.add(mediaServerItem);
+        }
+        return result;
+
+
+//        return mediaServerMapper.queryAll();
+    }
+
+    /**
+     * 鑾峰彇鍗曚釜zlm鏈嶅姟鍣�
+     * @param mediaServerId 鏈嶅姟id
+     * @return MediaServerItem
+     */
+    @Override
+    public IMediaServerItem getOne(String mediaServerId) {
+        if (mediaServerId ==null) return null;
+        IMediaServerItem mediaServerItem = zlmServers.get(mediaServerId);
+        if (mediaServerItem != null) {
+            mediaServerItem.setCount(zlmServerStatus.get(mediaServerId) == null ? 0 : zlmServerStatus.get(mediaServerId));
+            return mediaServerItem;
+        }else {
+            IMediaServerItem item = mediaServerMapper.queryOne(mediaServerId);
+            if (item != null) {
+                zlmServers.put(item.getId(), item);
+            }
+            return item;
+        }
+    }
+
+    @Override
+    public IMediaServerItem getOneByHostAndPort(String host, int port) {
+        return mediaServerMapper.queryOneByHostAndPort(host, port);
+    }
+
+    /**
+     * 澶勭悊zlm涓婄嚎
+     * @param zlmServerConfig zlm涓婄嚎鎼哄甫鐨勫弬鏁�
+     */
+    @Override
+    public void handLeZLMServerConfig(ZLMServerConfig zlmServerConfig) {
+        logger.info("[ {} ]-[ {}:{} ]宸茶繛鎺�",
+                zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
+
+        IMediaServerItem serverItem = getOne(zlmServerConfig.getGeneralMediaServerId());
+        String now = this.format.format(new Date(System.currentTimeMillis()));
+        if (serverItem != null) {
+            serverItem.setSecret(zlmServerConfig.getApiSecret());
+            serverItem.setIp(zlmServerConfig.getIp());
+            // 濡傛灉鏄厤缃枃浠朵腑鐨剒lm銆� 涔熷氨鏄粯璁lm銆� 涓�鍒囦互閰嶇疆鏂囦欢鍐呭涓哄噯
+            // docker閮ㄧ讲涓嶄細浣跨敤zlm閰嶇疆鐨勭鍙e彿;
+            // 鐩存帴缂栬瘧閮ㄧ讲鐨勪娇鐢ㄩ厤缃枃浠剁殑绔彛鍙凤紝濡傛灉zlm淇敼閰嶆敼浜嗛厤缃紝wvp鑷姩淇敼
+
+            if (serverItem.getId().equals(mediaConfig.getId())
+                    || (serverItem.getIp().equals(mediaConfig.getIp()) && serverItem.getHttpPort() == mediaConfig.getHttpPort())) {
+                // 閰嶇疆鏂囦欢鐨剒lm
+                mediaConfig.setId(zlmServerConfig.getGeneralMediaServerId());
+                mediaConfig.setUpdateTime(now);
+                if (mediaConfig.getHttpPort() == 0) mediaConfig.setHttpPort(zlmServerConfig.getHttpPort());
+                if (mediaConfig.getHttpSSlPort() == 0) mediaConfig.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
+                if (mediaConfig.getRtmpPort() == 0) mediaConfig.setRtmpPort(zlmServerConfig.getRtmpPort());
+                if (mediaConfig.getRtmpSSlPort() == 0) mediaConfig.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
+                if (mediaConfig.getRtspPort() == 0) mediaConfig.setRtspPort(zlmServerConfig.getRtspPort());
+                if (mediaConfig.getRtspSSLPort() == 0) mediaConfig.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
+                if (mediaConfig.getRtpProxyPort() == 0) mediaConfig.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
+                mediaServerMapper.update(mediaConfig);
+                serverItem = mediaConfig.getMediaSerItem();
+                setZLMConfig(mediaConfig);
+            }else {
+                if (!serverItem.isDocker()) {
+                    serverItem.setHttpPort(zlmServerConfig.getHttpPort());
+                    serverItem.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
+                    serverItem.setRtmpPort(zlmServerConfig.getRtmpPort());
+                    serverItem.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
+                    serverItem.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
+                    serverItem.setRtspPort(zlmServerConfig.getRtspPort());
+
+                }
+                serverItem.setUpdateTime(now);
+                mediaServerMapper.update(serverItem);
+                setZLMConfig(serverItem);
+            }
+        }else {
+            if (zlmServerConfig.getGeneralMediaServerId().equals(mediaConfig.getId())
+                    || (zlmServerConfig.getIp().equals(mediaConfig.getIp()) && zlmServerConfig.getHttpPort() == mediaConfig.getHttpPort())) {
+                mediaConfig.setId(zlmServerConfig.getGeneralMediaServerId());
+                mediaConfig.setCreateTime(now);
+                mediaConfig.setUpdateTime(now);
+                serverItem = mediaConfig;
+                mediaServerMapper.add(mediaConfig);
+            }else {
+                // 涓�涓柊鐨剒lm鎺ュ叆wvp
+                serverItem = new MediaServerItem(zlmServerConfig, sipIp);
+                serverItem.setCreateTime(now);
+                serverItem.setUpdateTime(now);
+                mediaServerMapper.add(serverItem);
+            }
+        }
+        // 鏇存柊缂撳瓨
+        if (zlmServerStatus.get(serverItem.getId()) == null) {
+            zlmServers.put(serverItem.getId(), serverItem);
+            zlmServerStatus.put(serverItem.getId(),0);
+        }
+        // 鏌ヨ鏈嶅姟娴佹暟閲�
+        IMediaServerItem finalServerItem = serverItem;
+        zlmresTfulUtils.getMediaList(serverItem, null, null, "rtmp",(mediaList ->{
+            Integer code = mediaList.getInteger("code");
+            if (code == 0) {
+                JSONArray data = mediaList.getJSONArray("data");
+                if (data != null) {
+                    zlmServerStatus.put(finalServerItem.getId(),data.size());
+                }else {
+                    zlmServerStatus.put(finalServerItem.getId(),0);
+                }
+
+            }
+        }));
+
+    }
+
+    /**
+     * 鏇存柊缂撳瓨
+     * @param mediaServerItem zlm鏈嶅姟
+     * @param count 鍦ㄧ嚎鏁�
+     * @param online 鍦ㄧ嚎鐘舵��
+     */
+    @Override
+    public void updateServerCatch(IMediaServerItem mediaServerItem, Integer count, Boolean online) {
+        if (mediaServerItem != null) {
+            zlmServers.put(mediaServerItem.getId(), mediaServerItem);
+            Collection<Integer> values = zlmServerStatus.values();
+            if (online != null && count != null) {
+                zlmServerStatus.put(mediaServerItem.getId(), count);
+            }
+        }
+    }
+
+    @Override
+    public void addCount(String mediaServerId) {
+        if (zlmServerStatus.get(mediaServerId) != null) {
+            zlmServerStatus.put(mediaServerId, zlmServerStatus.get(mediaServerId) + 1);
+        }
+    }
+
+    @Override
+    public void removeCount(String mediaServerId) {
+        if (zlmServerStatus.get(mediaServerId) != null) {
+            zlmServerStatus.put(mediaServerId, zlmServerStatus.get(mediaServerId) - 1);
+        }
+    }
+
+    /**
+     * 鑾峰彇璐熻浇鏈�浣庣殑鑺傜偣
+     * @return MediaServerItem
+     */
+    @Override
+    public IMediaServerItem getMediaServerForMinimumLoad() {
+        int mediaCount = -1;
+        String key = null;
+        System.out.println(JSON.toJSONString(zlmServerStatus));
+        if (zlmServerStatus.size() == 1) {
+            Map.Entry entry = zlmServerStatus.entrySet().iterator().next();
+            key= (String) entry.getKey();
+        }else {
+            for (String id : zlmServerStatus.keySet()) {
+                if (key == null) {
+                    key = id;
+                    mediaCount = zlmServerStatus.get(id);
+                }
+                if (zlmServerStatus.get(id) == 0) {
+                    key = id;
+                    break;
+                }else if (mediaCount >= zlmServerStatus.get(id)){
+                    mediaCount = zlmServerStatus.get(id);
+                    key = id;
+                }
+            }
+        }
+
+        if (key == null) {
+            logger.info("鑾峰彇璐熻浇鏈�浣庣殑鑺傜偣鏃舵棤鍦ㄧ嚎鑺傜偣");
+            return null;
+        }else{
+            return  zlmServers.get(key);
+        }
+    }
+
+    /**
+     * 瀵箊lm鏈嶅姟鍣ㄨ繘琛屽熀纭�閰嶇疆
+     * @param mediaServerItem 鏈嶅姟ID
+     */
+    @Override
+    public void setZLMConfig(IMediaServerItem mediaServerItem) {
+        logger.info("[ {} ]-[ {}:{} ]璁剧疆zlm",
+                mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+        String protocol = sslEnabled ? "https" : "http";
+        String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort);
+        String recordHookPrex = null;
+        if (mediaServerItem.getRecordAssistPort() != 0) {
+            recordHookPrex = String.format("http://127.0.0.1:%s/api/record", mediaServerItem.getRecordAssistPort());
+        }
+        Map<String, Object> param = new HashMap<>();
+        param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline
+        param.put("ffmpeg.cmd","%s -fflags nobuffer -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264  -f flv %s");
+        param.put("hook.enable","1");
+        param.put("hook.on_flow_report","");
+        param.put("hook.on_play",String.format("%s/on_play", hookPrex));
+        param.put("hook.on_http_access","");
+        param.put("hook.on_publish", String.format("%s/on_publish", hookPrex));
+        param.put("hook.on_record_mp4",recordHookPrex != null? String.format("%s/on_record_mp4", recordHookPrex): "");
+        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", hookPrex));
+        param.put("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex));
+        param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrex));
+        param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
+        param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
+        param.put("hook.timeoutSec","20");
+        param.put("general.streamNoneReaderDelayMS",mediaServerItem.getStreamNoneReaderDelayMS());
+
+        JSONObject responseJSON = zlmresTfulUtils.setServerConfig(mediaServerItem, param);
+
+        if (responseJSON != null && responseJSON.getInteger("code") == 0) {
+            logger.info("[ {} ]-[ {}:{} ]璁剧疆zlm鎴愬姛",
+                    mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+        }else {
+            logger.info("[ {} ]-[ {}:{} ]璁剧疆zlm澶辫触" + responseJSON.getString("msg"),
+                    mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
+        }
+    }
+}
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 e40f4b1..465ca88 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -6,6 +6,9 @@
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.service.IMediaService;
@@ -22,29 +25,52 @@
     private IVideoManagerStorager storager;
 
     @Autowired
+    private IMediaServerService mediaServerService;
+
+    @Autowired
     private ZLMRESTfulUtils zlmresTfulUtils;
 
 
 
     @Override
-    public StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks) {
-        return getStreamInfoByAppAndStream(app, stream, tracks, null);
+    public StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks) {
+        return getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, null);
     }
 
     @Override
-    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream) {
-        return getStreamInfoByAppAndStreamWithCheck(app, stream, null);
+    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, String addr) {
+        StreamInfo streamInfo = null;
+        IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
+        if (mediaInfo == null) {
+            return streamInfo;
+        }
+        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;
+                JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class);
+                JSONArray tracks = mediaJSON.getJSONArray("tracks");
+                streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks);
+            }
+        }
+        return streamInfo;
     }
 
     @Override
-    public StreamInfo getStreamInfoByAppAndStream(String app, String stream, JSONArray tracks, String addr) {
-        ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
+    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId) {
+        return getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, null);
+    }
+
+    @Override
+    public StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks, String addr) {
         StreamInfo streamInfoResult = new StreamInfo();
         streamInfoResult.setStreamId(stream);
         streamInfoResult.setApp(app);
         if (addr == null) {
             addr = mediaInfo.getStreamIp();
         }
+        streamInfoResult.setMediaServerId(mediaInfo.getId());
         streamInfoResult.setRtmp(String.format("rtmp://%s:%s/%s/%s", addr, mediaInfo.getRtmpPort(), app,  stream));
         streamInfoResult.setRtsp(String.format("rtsp://%s:%s/%s/%s", addr, mediaInfo.getRtspPort(), app,  stream));
         streamInfoResult.setFlv(String.format("http://%s:%s/%s/%s.flv", addr, mediaInfo.getHttpPort(), app,  stream));
@@ -60,19 +86,4 @@
         return streamInfoResult;
     }
 
-    @Override
-    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String addr) {
-        StreamInfo streamInfo = null;
-        JSONObject mediaList = zlmresTfulUtils.getMediaList(app, stream);
-        if (mediaList != null) {
-            if (mediaList.getInteger("code") == 0) {
-                JSONArray data = mediaList.getJSONArray("data");
-                if (data == null) return null;
-                JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class);
-                JSONArray tracks = mediaJSON.getJSONArray("tracks");
-                streamInfo = getStreamInfoByAppAndStream(app, stream, tracks, addr);
-            }
-        }
-        return streamInfo;
-    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
index 172d980..85a4f48 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -14,6 +14,9 @@
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
@@ -60,6 +63,9 @@
     private IMediaService mediaService;
 
     @Autowired
+    private IMediaServerService mediaServerService;
+
+    @Autowired
     private VideoStreamSessionManager streamSession;
 
     @Autowired
@@ -67,8 +73,18 @@
 
 
     @Override
-    public PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
+    public PlayResult play(IMediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
         PlayResult playResult = new PlayResult();
+        if (mediaServerItem == null) {
+            RequestMessage msg = new RequestMessage();
+            msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + playResult.getUuid());
+            WVPResult wvpResult = new WVPResult();
+            wvpResult.setCode(-1);
+            wvpResult.setMsg("鏈壘鍒板彲鐢ㄧ殑zlm");
+            msg.setData(wvpResult);
+            resultHolder.invokeResult(msg);
+            return playResult;
+        }
         Device device = storager.queryVideoDevice(deviceId);
         StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
         playResult.setDevice(device);
@@ -82,7 +98,7 @@
         result.onTimeout(()->{
             logger.warn(String.format("璁惧鐐规挱瓒呮椂锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId));
             // 閲婃斁rtpserver
-            cmder.closeRTPServer(playResult.getDevice(), channelId);
+            mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
             RequestMessage msg = new RequestMessage();
             msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + playResult.getUuid());
             WVPResult wvpResult = new WVPResult();
@@ -115,9 +131,10 @@
                     WVPResult wvpResult = (WVPResult)responseEntity.getBody();
                     if (wvpResult.getCode() == 0) {
                         StreamInfo streamInfoForSuccess = (StreamInfo)wvpResult.getData();
+                        IMediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId());
                         String streamUrl = streamInfoForSuccess.getFmp4();
                         // 璇锋眰鎴浘
-                        zlmresTfulUtils.getSnap(streamUrl, 15, 1, path, fileName);
+                        zlmresTfulUtils.getSnap(mediaInfo, streamUrl, 15, 1, path, fileName);
                     }
                 }
             } catch (FileNotFoundException e) {
@@ -126,17 +143,17 @@
         });
         if (streamInfo == null) {
             // 鍙戦�佺偣鎾秷鎭�
-            cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
+            cmder.playStreamCmd(mediaServerItem, device, channelId, (IMediaServerItem mediaServerItemInUse, JSONObject response) -> {
                 logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
-                onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
+                onPublishHandlerForPlay(mediaServerItemInUse, response, deviceId, channelId, uuid.toString());
                 if (hookEvent != null) {
-                    hookEvent.response(response);
+                    hookEvent.response(mediaServerItem, response);
                 }
-            }, event -> {
+            }, (event) -> {
                 RequestMessage msg = new RequestMessage();
                 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
                 Response response = event.getResponse();
-                cmder.closeRTPServer(playResult.getDevice(), channelId);
+                mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
                 WVPResult wvpResult = new WVPResult();
                 wvpResult.setCode(-1);
                 wvpResult.setMsg(String.format("鐐规挱澶辫触锛� 閿欒鐮侊細 %s, %s", response.getStatusCode(), response.getReasonPhrase()));
@@ -158,7 +175,10 @@
                 resultHolder.invokeResult(msg);
                 return playResult;
             }
-            JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
+            String mediaServerId = streamInfo.getMediaServerId();
+            IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
+
+            JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
             if (rtpInfo != null && rtpInfo.getBoolean("exist")) {
                 RequestMessage msg = new RequestMessage();
                 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
@@ -171,16 +191,16 @@
 
                 resultHolder.invokeResult(msg);
                 if (hookEvent != null) {
-                    hookEvent.response(JSONObject.parseObject(JSON.toJSONString(streamInfo)));
+                    hookEvent.response(mediaServerItem, JSONObject.parseObject(JSON.toJSONString(streamInfo)));
                 }
             } else {
                 redisCatchStorage.stopPlay(streamInfo);
                 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
-                cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
+                cmder.playStreamCmd(mediaServerItem, device, channelId, (IMediaServerItem mediaServerItemInuse, JSONObject response) -> {
                     logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
-                    onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
-                }, event -> {
-                    cmder.closeRTPServer(playResult.getDevice(), channelId);
+                    onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid.toString());
+                }, (event) -> {
+                    mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
                     RequestMessage msg = new RequestMessage();
                     msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
                     Response response = event.getResponse();
@@ -198,10 +218,10 @@
     }
 
     @Override
-    public void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, String uuid) {
+    public void onPublishHandlerForPlay(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
         RequestMessage msg = new RequestMessage();
         msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
-        StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid);
+        StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid);
         if (streamInfo != null) {
             DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
             if (deviceChannel != null) {
@@ -234,10 +254,26 @@
     }
 
     @Override
-    public void onPublishHandlerForPlayBack(JSONObject resonse, String deviceId, String channelId, String uuid) {
+    public IMediaServerItem getNewMediaServerItem(Device device) {
+        if (device == null) return null;
+        String mediaServerId = device.getMediaServerId();
+        IMediaServerItem mediaServerItem = null;
+        if (mediaServerId == null) {
+            mediaServerItem = mediaServerService.getMediaServerForMinimumLoad();
+        }else {
+            mediaServerItem = mediaServerService.getOne(mediaServerId);
+        }
+        if (mediaServerItem == null) {
+            logger.warn("鐐规挱鏃舵湭鎵惧埌鍙娇鐢ㄧ殑ZLM...");
+        }
+        return mediaServerItem;
+    }
+
+    @Override
+    public void onPublishHandlerForPlayBack(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
         RequestMessage msg = new RequestMessage();
         msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
-        StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid);
+        StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid);
         if (streamInfo != null) {
             redisCatchStorage.startPlayback(streamInfo);
             msg.setData(JSON.toJSONString(streamInfo));
@@ -249,10 +285,10 @@
         }
     }
 
-    public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) {
+    public StreamInfo onPublishHandler(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
         String streamId = resonse.getString("stream");
         JSONArray tracks = resonse.getJSONArray("tracks");
-        StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream("rtp", streamId, tracks);
+        StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem,"rtp", streamId, tracks);
         streamInfo.setDeviceID(deviceId);
         streamInfo.setChannelId(channelId);
         return streamInfo;
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 2eb99b8..fe49c3b 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
@@ -2,10 +2,12 @@
 
 import com.alibaba.fastjson.JSONObject;
 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
-import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
 import com.genersoft.iot.vmp.service.IGbStreamService;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
@@ -13,6 +15,8 @@
 import com.genersoft.iot.vmp.storager.dao.StreamProxyMapper;
 import com.genersoft.iot.vmp.service.IStreamProxyService;
 import com.github.pagehelper.PageInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -25,6 +29,8 @@
 @Service
 public class StreamProxyServiceImpl implements IStreamProxyService {
 
+    private final static Logger logger = LoggerFactory.getLogger(StreamProxyServiceImpl.class);
+
     @Autowired
     private IVideoManagerStorager videoManagerStorager;
 
@@ -32,7 +38,7 @@
     private IRedisCatchStorage redisCatchStorage;
 
     @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
+    private ZLMRESTfulUtils zlmresTfulUtils;;
 
     @Autowired
     private StreamProxyMapper streamProxyMapper;
@@ -46,15 +52,28 @@
     @Autowired
     private IGbStreamService gbStreamService;
 
+    @Autowired
+    private IMediaServerService mediaServerService;
+
 
     @Override
     public String save(StreamProxyItem param) {
-        ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
+        IMediaServerItem mediaInfo;
+        if ("auto".equals(param.getMediaServerId())){
+            mediaInfo = mediaServerService.getMediaServerForMinimumLoad();
+        }else {
+            mediaInfo = mediaServerService.getOne(param.getMediaServerId());
+        }
+        if (mediaInfo == null) {
+            logger.warn("淇濆瓨浠g悊鏈壘鍒板湪绾跨殑ZLM...");
+            return "淇濆瓨澶辫触";
+        }
         String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(),
                 param.getStream() );
         param.setDst_url(dstUrl);
         StringBuffer result = new StringBuffer();
         boolean streamLive = false;
+        param.setMediaServerId(mediaInfo.getId());
         // 鏇存柊
         if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) {
             if (videoManagerStorager.updateStreamProxy(param)) {
@@ -81,6 +100,8 @@
                         videoManagerStorager.updateStreamProxy(param);
                     }
                 }
+            }else {
+                result.append("淇濆瓨澶辫触");
             }
 
         }
@@ -99,11 +120,18 @@
     @Override
     public JSONObject addStreamProxyToZlm(StreamProxyItem param) {
         JSONObject result = null;
+        IMediaServerItem mediaServerItem = null;
+        if (param.getMediaServerId() == null) {
+            logger.warn("娣诲姞浠g悊鏃禡ediaServerId 涓簄ull");
+            return null;
+        }else {
+            mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
+        }
         if ("default".equals(param.getType())){
-            result = zlmresTfulUtils.addStreamProxy(param.getApp(), param.getStream(), param.getUrl(),
+            result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl(),
                     param.isEnable_hls(), param.isEnable_mp4(), param.getRtp_type());
         }else if ("ffmpeg".equals(param.getType())) {
-            result = zlmresTfulUtils.addFFmpegSource(param.getSrc_url(), param.getDst_url(),
+            result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrc_url(), param.getDst_url(),
                     param.getTimeout_ms() + "", param.isEnable_hls(), param.isEnable_mp4(),
                     param.getFfmpeg_cmd_key());
         }
@@ -112,8 +140,9 @@
 
     @Override
     public JSONObject removeStreamProxyFromZlm(StreamProxyItem param) {
-        JSONObject result = zlmresTfulUtils.closeStreams(param.getApp(), param.getStream());
-
+        if (param ==null) return null;
+        IMediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
+        JSONObject result = zlmresTfulUtils.closeStreams(mediaServerItem, param.getApp(), param.getStream());
         return result;
     }
 
@@ -124,17 +153,18 @@
 
     @Override
     public void del(String app, String stream) {
-        StreamProxyItem streamProxyItem = new StreamProxyItem();
-        streamProxyItem.setApp(app);
-        streamProxyItem.setStream(stream);
-        JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem);
-        if (jsonObject.getInteger("code") == 0) {
+        StreamProxyItem streamProxyItem = videoManagerStorager.queryStreamProxy(app, stream);
+        if (streamProxyItem != null) {
             videoManagerStorager.deleteStreamProxy(app, stream);
-            // 濡傛灉鍏宠仈浜嗗浗鏍囬偅涔堢Щ闄ゅ叧鑱�
-            gbStreamMapper.del(app, stream);
-            platformGbStreamMapper.delByAppAndStream(app, stream);
-            // TODO 濡傛灉鍏宠仈鐨勬帹娴侊紝 閭d箞鐘舵�佽缃负绂荤嚎
+            JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem);
+            if (jsonObject != null && jsonObject.getInteger("code") == 0) {
+                // 濡傛灉鍏宠仈浜嗗浗鏍囬偅涔堢Щ闄ゅ叧鑱�
+                gbStreamMapper.del(app, stream);
+                platformGbStreamMapper.delByAppAndStream(app, stream);
+                // TODO 濡傛灉鍏宠仈鐨勬帹娴侊紝 閭d箞鐘舵�佽缃负绂荤嚎
+            }
         }
+
     }
 
     @Override
@@ -168,9 +198,9 @@
     }
 
     @Override
-    public JSONObject getFFmpegCMDs() {
+    public JSONObject getFFmpegCMDs(IMediaServerItem mediaServerItem) {
         JSONObject result = new JSONObject();
-        JSONObject mediaServerConfigResuly = zlmresTfulUtils.getMediaServerConfig();
+        JSONObject mediaServerConfigResuly = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
         if (mediaServerConfigResuly != null && mediaServerConfigResuly.getInteger("code") == 0
                 && mediaServerConfigResuly.getJSONArray("data").size() > 0){
             JSONObject mediaServerConfig = mediaServerConfigResuly.getJSONArray("data").getJSONObject(0);
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 7ebfb54..3692e54 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
@@ -5,9 +5,13 @@
 import com.alibaba.fastjson.TypeReference;
 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 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.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
 import com.genersoft.iot.vmp.storager.dao.StreamPushMapper;
 import com.github.pagehelper.PageHelper;
@@ -32,8 +36,14 @@
     @Autowired
     private ZLMRESTfulUtils zlmresTfulUtils;
 
+    @Autowired
+    private IRedisCatchStorage redisCatchStorage;
+
+    @Autowired
+    private IMediaServerService mediaServerService;
+
     @Override
-    public List<StreamPushItem> handleJSON(String jsonData) {
+    public List<StreamPushItem> handleJSON(String jsonData, IMediaServerItem mediaServerItem) {
         if (jsonData == null) return null;
 
         Map<String, StreamPushItem> result = new HashMap<>();
@@ -50,6 +60,7 @@
             if (streamPushItem == null) {
                 streamPushItem = new StreamPushItem();
                 streamPushItem.setApp(item.getApp());
+                streamPushItem.setMediaServerId(mediaServerItem.getId());
                 streamPushItem.setStream(item.getStream());
                 streamPushItem.setAliveSecond(item.getAliveSecond());
                 streamPushItem.setCreateStamp(item.getCreateStamp());
@@ -87,7 +98,8 @@
     @Override
     public boolean removeFromGB(GbStream stream) {
         int del = gbStreamMapper.del(stream.getApp(), stream.getStream());
-        JSONObject mediaList = zlmresTfulUtils.getMediaList(stream.getApp(), stream.getStream());
+        IMediaServerItem mediaInfo = mediaServerService.getOne(stream.getMediaServerId());
+        JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, stream.getApp(), stream.getStream());
         if (mediaList == null) {
             streamPushMapper.del(stream.getApp(), stream.getStream());
         }
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 56c31c1..a4edb08 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -2,10 +2,11 @@
 
 import com.alibaba.fastjson.JSONObject;
 import com.genersoft.iot.vmp.common.StreamInfo;
-import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 
 import java.util.List;
 import java.util.Map;
@@ -39,19 +40,6 @@
     StreamInfo queryPlaybackByStreamId(String steamId);
 
     StreamInfo queryPlayByDevice(String deviceId, String channelId);
-
-    /**
-     * 鏇存柊娴佸獟浣撲俊鎭�
-     * @param ZLMServerConfig
-     * @return
-     */
-    boolean updateMediaInfo(ZLMServerConfig ZLMServerConfig);
-
-    /**
-     * 鑾峰彇娴佸獟浣撲俊鎭�
-     * @return
-     */
-    ZLMServerConfig getMediaInfo();
 
     Map<String, StreamInfo> queryPlayByDeviceId(String deviceId);
 
@@ -115,6 +103,13 @@
     void clearCatchByDeviceId(String deviceId);
 
     /**
+     * 鑾峰彇mediaServer鑺傜偣
+     * @param mediaServerId
+     * @return
+     */
+//    MediaServerItem getMediaInfo(String mediaServerId);
+
+    /**
      * 璁剧疆鎵�鏈夎澶囩绾�
      */
     void outlineForAll();
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
index 5d838c5..97c3794 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -3,6 +3,8 @@
 import java.util.List;
 
 import com.genersoft.iot.vmp.gb28181.bean.*;
+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.StreamProxyItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
@@ -365,4 +367,12 @@
 	 * @param online
 	 */
 	void updateParentPlatformStatus(String platformGbID, boolean online);
+
+	/**
+	 * 鏇存柊濯掍綋鑺傜偣
+	 * @param mediaServerItem
+	 */
+	void updateMediaServer(MediaServerItem mediaServerItem);
+
+	List<StreamProxyItem> getStreamProxyListForEnableInMediaServer(String id, boolean b);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
index 80397d2..230afbc 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
@@ -12,9 +12,10 @@
 public interface GbStreamMapper {
 
     @Insert("INSERT INTO gb_stream (app, stream, gbId, name, " +
-            "longitude, latitude, streamType, status) VALUES" +
+            "longitude, latitude, streamType, mediaServerId, status) VALUES" +
             "('${app}', '${stream}', '${gbId}', '${name}', " +
-            "'${longitude}', '${latitude}', '${streamType}', ${status})")
+            "'${longitude}', '${latitude}', '${streamType}', " +
+            "'${mediaServerId}', ${status})")
     int add(GbStream gbStream);
 
     @Update("UPDATE gb_stream " +
@@ -25,6 +26,7 @@
             "streamType=#{streamType}," +
             "longitude=#{longitude}, " +
             "latitude=#{latitude}," +
+            "mediaServerId=#{mediaServerId}," +
             "status=${status} " +
             "WHERE app=#{app} AND stream=#{stream} AND gbId=#{gbId}")
     int update(GbStream gbStream);
@@ -52,4 +54,7 @@
             "SET status=${status} " +
             "WHERE app=#{app} AND stream=#{stream}")
     void setStatus(String app, String stream, boolean status);
+
+    @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs LEFT JOIN  platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream WHERE mediaServerId=#{mediaServerId} ")
+    List<GbStream> selectAllByMediaServerId(String mediaServerId);
 }
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
new file mode 100644
index 0000000..475ec6d
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
@@ -0,0 +1,99 @@
+package com.genersoft.iot.vmp.storager.dao;
+
+import com.genersoft.iot.vmp.conf.MediaConfig;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+
+@Mapper
+@Repository
+public interface MediaServerMapper {
+
+    @Insert("INSERT INTO media_server (" +
+            "id, " +
+            "ip, " +
+            "hookIp, " +
+            "sdpIp, " +
+            "streamIp, " +
+            "httpPort, " +
+            "httpSSlPort, " +
+            "rtmpPort, " +
+            "rtmpSSlPort, " +
+            "rtpProxyPort, " +
+            "rtspPort, " +
+            "rtspSSLPort, " +
+            "autoConfig, " +
+            "secret, " +
+            "streamNoneReaderDelayMS, " +
+            "rtpEnable, " +
+            "rtpPortRange, " +
+            "recordAssistPort, " +
+            "createTime, " +
+            "updateTime" +
+            ") VALUES " +
+            "(" +
+            "'${id}', " +
+            "'${ip}', " +
+            "'${hookIp}', " +
+            "'${sdpIp}', " +
+            "'${streamIp}', " +
+            "${httpPort}, " +
+            "${httpSSlPort}, " +
+            "${rtmpPort}, " +
+            "${rtmpSSlPort}, " +
+            "${rtpProxyPort}, " +
+            "${rtspPort}, " +
+            "${rtspSSLPort}, " +
+            "${autoConfig}, " +
+            "'${secret}', " +
+            "${streamNoneReaderDelayMS}, " +
+            "${rtpEnable}, " +
+            "'${rtpPortRange}', " +
+            "${recordAssistPort}, " +
+            "'${createTime}', " +
+            "'${updateTime}')")
+    int add(IMediaServerItem mediaServerItem);
+
+    @Update(value = {" <script>" +
+            "UPDATE media_server " +
+            "SET updateTime='${updateTime}'" +
+            "<if test=\"ip != null\">, ip='${ip}'</if>" +
+            "<if test=\"hookIp != null\">, hookIp='${hookIp}'</if>" +
+            "<if test=\"sdpIp != null\">, sdpIp='${sdpIp}'</if>" +
+            "<if test=\"streamIp != null\">, streamIp='${streamIp}'</if>" +
+            "<if test=\"httpPort != null\">, httpPort=${httpPort}</if>" +
+            "<if test=\"httpSSlPort != null\">, httpSSlPort=${httpSSlPort}</if>" +
+            "<if test=\"rtmpPort != null\">, rtmpPort=${rtmpPort}</if>" +
+            "<if test=\"rtmpSSlPort != null\">, rtmpSSlPort=${rtmpSSlPort}</if>" +
+            "<if test=\"rtpProxyPort != null\">, rtpProxyPort=${rtpProxyPort}</if>" +
+            "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" +
+            "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" +
+            "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" +
+            "<if test=\"streamNoneReaderDelayMS != null\">, streamNoneReaderDelayMS=${streamNoneReaderDelayMS}</if>" +
+            "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" +
+            "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" +
+            "<if test=\"secret != null\">, secret='${secret}'</if>" +
+            "<if test=\"recordAssistPort != null\">, recordAssistPort=${recordAssistPort}</if>" +
+            "WHERE id='${id}'"+
+            " </script>"})
+    int update(IMediaServerItem mediaServerItem);
+
+    @Select("SELECT * FROM media_server WHERE id='${id}'")
+    MediaServerItem queryOne(String id);
+
+    @Select("SELECT * FROM media_server")
+    List<MediaServerItem> queryAll();
+
+    @Select("DELETE FROM media_server WHERE id='${id}'")
+    int delOne(String secret);
+
+    @Select("SELECT * FROM media_server WHERE ip='${host}' and httpPort=${port}")
+    MediaServerItem queryOneByHostAndPort(String host, int port);
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
index 3f53c36..7346da5 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
@@ -10,10 +10,10 @@
 @Repository
 public interface StreamProxyMapper {
 
-    @Insert("INSERT INTO stream_proxy (type, app, stream, url, src_url, dst_url, " +
-            "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable) VALUES" +
-            "('${type}','${app}', '${stream}', '${url}', '${src_url}', '${dst_url}', " +
-            "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable} )")
+    @Insert("INSERT INTO stream_proxy (type, app, stream,mediaServerId, url, src_url, dst_url, " +
+            "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable, createTime) VALUES" +
+            "('${type}','${app}', '${stream}', '${mediaServerId}','${url}', '${src_url}', '${dst_url}', " +
+            "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable}, '${createTime}' )")
     int add(StreamProxyItem streamProxyDto);
 
     @Update("UPDATE stream_proxy " +
@@ -21,6 +21,7 @@
             "app=#{app}," +
             "stream=#{stream}," +
             "url=#{url}, " +
+            "mediaServerId=#{mediaServerId}, " +
             "src_url=#{src_url}," +
             "dst_url=#{dst_url}, " +
             "timeout_ms=#{timeout_ms}, " +
@@ -35,12 +36,17 @@
     @Delete("DELETE FROM stream_proxy WHERE app=#{app} AND stream=#{stream}")
     int del(String app, String stream);
 
-    @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream")
+    @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream order by st.createTime desc")
     List<StreamProxyItem> selectAll();
 
-    @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=${enable}")
+    @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=${enable} order by st.createTime desc")
     List<StreamProxyItem> selectForEnable(boolean enable);
 
-    @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.app=#{app} AND st.stream=#{stream}")
+    @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.app=#{app} AND st.stream=#{stream} order by st.createTime desc")
     StreamProxyItem selectOne(String app, String stream);
+
+    @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st " +
+            "LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " +
+            "WHERE st.enable=${enable} and st.mediaServerId = '${id}' order by st.createTime desc")
+    List<StreamProxyItem> selectForEnableInMediaServer(String id, boolean enable);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
index 455aa2c..41e4c44 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
@@ -11,14 +11,15 @@
 public interface StreamPushMapper {
 
     @Insert("INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
-            "createStamp, aliveSecond) VALUES" +
+            "createStamp, aliveSecond, mediaServerId) VALUES" +
             "('${app}', '${stream}', '${totalReaderCount}', '${originType}', '${originTypeStr}', " +
-            "'${createStamp}', '${aliveSecond}' )")
+            "'${createStamp}', '${aliveSecond}', '${mediaServerId}' )")
     int add(StreamPushItem streamPushItem);
 
     @Update("UPDATE stream_push " +
             "SET app=#{app}," +
             "stream=#{stream}," +
+            "mediaServerId=#{mediaServerId}," +
             "totalReaderCount=#{totalReaderCount}, " +
             "originType=#{originType}," +
             "originTypeStr=#{originTypeStr}, " +
@@ -41,10 +42,10 @@
 
     @Insert("<script>"  +
             "INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
-            "createStamp, aliveSecond) " +
+            "createStamp, aliveSecond, mediaServerId) " +
             "VALUES <foreach collection='streamPushItems' item='item' index='index' >" +
             "( '${item.app}', '${item.stream}', '${item.totalReaderCount}', '${item.originType}', " +
-            "'${item.originTypeStr}','${item.createStamp}', '${item.aliveSecond}' )" +
+            "'${item.originTypeStr}','${item.createStamp}', '${item.aliveSecond}', '${item.mediaServerId}' )" +
             " </foreach>" +
             "</script>")
     void addAll(List<StreamPushItem> streamPushItems);
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 86909c7..eafb8a0 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -5,6 +5,8 @@
 import com.genersoft.iot.vmp.common.VideoManagerConstants;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
 import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
@@ -85,26 +87,6 @@
                 channelId));
         if (playLeys == null || playLeys.size() == 0) return null;
         return (StreamInfo)redis.get(playLeys.get(0).toString());
-    }
-
-    /**
-     * 鏇存柊娴佸獟浣撲俊鎭�
-     * @param ZLMServerConfig
-     * @return
-     */
-    @Override
-    public boolean updateMediaInfo(ZLMServerConfig ZLMServerConfig) {
-        ZLMServerConfig.setUpdateTime(format.format(new Date(System.currentTimeMillis())));
-        return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX, ZLMServerConfig);
-    }
-
-    /**
-     * 鑾峰彇娴佸獟浣撲俊鎭�
-     * @return
-     */
-    @Override
-    public ZLMServerConfig getMediaInfo() {
-        return (ZLMServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX);
     }
 
     @Override
@@ -297,7 +279,7 @@
 
     @Override
     public void outlineForAll() {
-        List<Object> onlineDevices = redis.scan(String.format("%S*", VideoManagerConstants.KEEPLIVEKEY_PREFIX));
+        List<Object> onlineDevices = redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX + "*" );
         for (int i = 0; i < onlineDevices.size(); i++) {
             String key = (String) onlineDevices.get(i);
             redis.del(key);
@@ -308,4 +290,5 @@
     public void updateWVPInfo(JSONObject jsonObject) {
 
     }
+
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
index bbe8c2b..4e24753 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
@@ -5,6 +5,7 @@
 
 import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -69,6 +70,9 @@
 
 	@Autowired
     private VideoStreamSessionManager streamSession;
+
+	@Autowired
+    private MediaServerMapper mediaServerMapper;
 
 	private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
@@ -459,6 +463,8 @@
 		boolean result = false;
 		streamProxyItem.setStreamType("proxy");
 		streamProxyItem.setStatus(true);
+		String now = this.format.format(new Date(System.currentTimeMillis()));
+		streamProxyItem.setCreateTime(now);
 		try {
 			if (gbStreamMapper.add(streamProxyItem)<0 || streamProxyMapper.add(streamProxyItem) < 0) {
 				//浜嬪姟鍥炴粴
@@ -467,6 +473,7 @@
 			result = true;
 			dataSourceTransactionManager.commit(transactionStatus);     //鎵嬪姩鎻愪氦
 		}catch (Exception e) {
+			logger.error("鍚戞暟鎹簱娣诲姞娴佷唬鐞嗗け璐ワ細", e);
 			dataSourceTransactionManager.rollback(transactionStatus);
 		}
 		return result;
@@ -599,4 +606,21 @@
 	public void updateParentPlatformStatus(String platformGbID, boolean online) {
 		platformMapper.updateParentPlatformStatus(platformGbID, online);
 	}
+
+	@Override
+	public void updateMediaServer(MediaServerItem mediaServerItem) {
+		String now = this.format.format(new Date(System.currentTimeMillis()));
+		mediaServerItem.setUpdateTime(now);
+		if (mediaServerMapper.queryOne(mediaServerItem.getId()) != null) {
+			mediaServerMapper.update(mediaServerItem);
+		}else {
+			mediaServerItem.setCreateTime(now);
+			mediaServerMapper.add(mediaServerItem);
+		}
+	}
+
+	@Override
+	public List<StreamProxyItem> getStreamProxyListForEnableInMediaServer(String id, boolean enable) {
+		return streamProxyMapper.selectForEnableInMediaServer(id, enable);
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java
index eab00bc..6caf8d9 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java
@@ -25,6 +25,7 @@
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
 
@@ -78,7 +79,7 @@
 		cmder.deviceBasicConfigCmd(device, channelId, name, expiration, heartBeatInterval, heartBeatCount, event -> {
 			Response response = event.getResponse();
 			RequestMessage msg = new RequestMessage();
-			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
 			msg.setData(String.format("璁惧閰嶇疆鎿嶄綔澶辫触锛岄敊璇爜锛� %s, %s", response.getStatusCode(), response.getReasonPhrase()));
 			resultHolder.invokeResult(msg);
 		});
@@ -87,7 +88,7 @@
 			logger.warn(String.format("璁惧閰嶇疆鎿嶄綔瓒呮椂, 璁惧鏈繑鍥炲簲绛旀寚浠�"));
 			// 閲婃斁rtpserver
 			RequestMessage msg = new RequestMessage();
-			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
 			JSONObject json = new JSONObject();
 			json.put("DeviceID", deviceId);
 			json.put("Status", "Timeout");
@@ -95,7 +96,7 @@
 			msg.setData(json); //("鐪嬪畧浣嶆帶鍒舵搷浣滆秴鏃�, 璁惧鏈繑鍥炲簲绛旀寚浠�");
 			resultHolder.invokeResult(msg);
 		});
-		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
+		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
 		return result;
 	}
 
@@ -123,7 +124,7 @@
 		cmder.deviceConfigQuery(device, channelId, configType, event -> {
 			Response response = event.getResponse();
 			RequestMessage msg = new RequestMessage();
-			msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
 			msg.setData(String.format("鑾峰彇璁惧閰嶇疆澶辫触锛岄敊璇爜锛� %s, %s", response.getStatusCode(), response.getReasonPhrase()));
 			resultHolder.invokeResult(msg);
 		});
@@ -132,11 +133,11 @@
 			logger.warn(String.format("鑾峰彇璁惧閰嶇疆瓒呮椂"));
 			// 閲婃斁rtpserver
 			RequestMessage msg = new RequestMessage();
-			msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
 			msg.setData("Timeout. Device did not response to this command.");
 			resultHolder.invokeResult(msg);
 		});
-		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
+		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
 		return result;
 	}
 
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
index 45059aa..874d9a9 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
@@ -26,6 +26,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
 
@@ -97,7 +98,7 @@
         cmder.recordCmd(device, channelId, recordCmdStr, event -> {
             Response response = event.getResponse();
             RequestMessage msg = new RequestMessage();
-			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
 			msg.setData(String.format("寮�濮�/鍋滄褰曞儚鎿嶄綔澶辫触锛岄敊璇爜锛� %s, %s", response.getStatusCode(), response.getReasonPhrase()));
 			resultHolder.invokeResult(msg);
 		});
@@ -106,11 +107,11 @@
 			logger.warn(String.format("寮�濮�/鍋滄褰曞儚鎿嶄綔瓒呮椂, 璁惧鏈繑鍥炲簲绛旀寚浠�"));
 			// 閲婃斁rtpserver
 			RequestMessage msg = new RequestMessage();
-			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
 			msg.setData("Timeout. Device did not response to this command.");
 			resultHolder.invokeResult(msg);
 		});
-		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
+		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
 		return result;
 	}
 
@@ -254,7 +255,7 @@
 		cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> {
 			Response response = event.getResponse();
 			RequestMessage msg = new RequestMessage();
-			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
 			msg.setData(String.format("鐪嬪畧浣嶆帶鍒舵搷浣滃け璐ワ紝閿欒鐮侊細 %s, %s", response.getStatusCode(), response.getReasonPhrase()));
 			resultHolder.invokeResult(msg);
 		});
@@ -263,7 +264,7 @@
 			logger.warn(String.format("鐪嬪畧浣嶆帶鍒舵搷浣滆秴鏃�, 璁惧鏈繑鍥炲簲绛旀寚浠�"));
 			// 閲婃斁rtpserver
 			RequestMessage msg = new RequestMessage();
-			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
 			JSONObject json = new JSONObject();
 			json.put("DeviceID", deviceId);
 			json.put("Status", "Timeout");
@@ -271,7 +272,7 @@
 			msg.setData(json); //("鐪嬪畧浣嶆帶鍒舵搷浣滆秴鏃�, 璁惧鏈繑鍥炲簲绛旀寚浠�");
 			resultHolder.invokeResult(msg);
 		});
-		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
+		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
 		return result;
 	}
 }
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 5db9478..450c54a 100644
--- 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
@@ -43,11 +43,13 @@
     @ApiImplicitParams({
             @ApiImplicitParam(name = "app", value = "搴旂敤鍚�", dataTypeClass = String.class),
             @ApiImplicitParam(name = "stream", value = "娴乮d", dataTypeClass = String.class),
+            @ApiImplicitParam(name = "mediaServerId", value = "濯掍綋鏈嶅姟鍣╥d", dataTypeClass = String.class),
     })
     @GetMapping(value = "/stream_info_by_app_and_stream")
     @ResponseBody
-    public StreamInfo getStreamInfoByAppAndStream(String app, String stream){
-        return mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream);
+    public StreamInfo getStreamInfoByAppAndStream(@RequestParam String app, @RequestParam String stream, @RequestParam String mediaServerId){
+
+        return mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream,mediaServerId);
     }
 
 
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 4297bb2..aae9cce 100644
--- 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
@@ -8,6 +8,9 @@
 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.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
@@ -72,6 +75,9 @@
 	@Autowired
 	private IMediaService mediaService;
 
+	@Autowired
+	private IMediaServerService mediaServerService;
+
 	@ApiOperation("寮�濮嬬偣鎾�")
 	@ApiImplicitParams({
 			@ApiImplicitParam(name = "deviceId", value = "璁惧ID", dataTypeClass = String.class),
@@ -81,8 +87,10 @@
 	public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId,
 													   @PathVariable String channelId) {
 
-		PlayResult playResult = playService.play(deviceId, channelId, null, null);
-
+		// 鑾峰彇鍙敤鐨剒lm
+		Device device = storager.queryVideoDevice(deviceId);
+		IMediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
+		PlayResult playResult = playService.play(newMediaServerItem, deviceId, channelId, null, null);
 
 		return playResult.getResult();
 	}
@@ -102,8 +110,8 @@
 
 		// 褰曞儚鏌ヨ浠hannelId浣滀负deviceId鏌ヨ
 		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_STOP + uuid, result);
-
-		cmder.streamByeCmd(deviceId, channelId, event -> {
+		Device device = storager.queryVideoDevice(deviceId);
+		cmder.streamByeCmd(deviceId, channelId, (event) -> {
 			StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
 			if (streamInfo == null) {
 				RequestMessage msg = new RequestMessage();
@@ -120,6 +128,7 @@
 				msg.setData(String.format("success"));
 				resultHolder.invokeResult(msg);
 			}
+			mediaServerService.closeRTPServer(device, channelId);
 		});
 
 		if (deviceId != null || channelId != null) {
@@ -165,16 +174,16 @@
 			logger.warn("瑙嗛杞爜API璋冪敤澶辫触锛�, 瑙嗛娴佸凡缁忓仠姝�!");
 			return new ResponseEntity<String>("鏈壘鍒拌棰戞祦淇℃伅, 瑙嗛娴佸彲鑳藉凡缁忓仠姝�", HttpStatus.OK);
 		}
-		JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
+		IMediaServerItem mediaInfo = mediaServerService.getOne(streamInfo.getMediaServerId());
+		JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
 		if (!rtpInfo.getBoolean("exist")) {
 			logger.warn("瑙嗛杞爜API璋冪敤澶辫触锛�, 瑙嗛娴佸凡鍋滄鎺ㄦ祦!");
 			return new ResponseEntity<String>("鎺ㄦ祦淇℃伅鍦ㄦ祦濯掍綋涓笉瀛樺湪, 瑙嗛娴佸彲鑳藉凡鍋滄鎺ㄦ祦", HttpStatus.OK);
 		} else {
-			ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
 			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(srcUrl, dstUrl, "1000000", true, false, null);
+			JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(mediaInfo, srcUrl, dstUrl, "1000000", true, false, null);
 			logger.info(jsonObject.toJSONString());
 			JSONObject result = new JSONObject();
 			if (jsonObject != null && jsonObject.getInteger("code") == 0) {
@@ -182,7 +191,7 @@
 				JSONObject data = jsonObject.getJSONObject("data");
 				if (data != null) {
 				   	result.put("key", data.getString("key"));
-					StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStreamWithCheck("convert", streamId);
+					StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStreamWithCheck("convert", streamId, mediaInfo.getId());
 					result.put("data", streamInfoResult);
 				}
 			}else {
@@ -203,25 +212,38 @@
 			@ApiImplicitParam(name = "key", value = "瑙嗛娴乲ey", dataTypeClass = String.class),
 	})
 	@PostMapping("/convertStop/{key}")
-	public ResponseEntity<String> playConvertStop(@PathVariable String key) {
-
-		JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(key);
-		logger.info(jsonObject.toJSONString());
+	public ResponseEntity<String> playConvertStop(@PathVariable String key, String mediaServerId) {
 		JSONObject result = new JSONObject();
-		if (jsonObject != null && jsonObject.getInteger("code") == 0) {
-			result.put("code", 0);
-			JSONObject data = jsonObject.getJSONObject("data");
-			if (data != null && data.getBoolean("flag")) {
-				result.put("code", "0");
-				result.put("msg", "success");
-			}else {
-
-			}
-		}else {
-			result.put("code", 1);
-			result.put("msg", "delFFmpegSource fail");
+		if (mediaServerId == null) {
+			result.put("code", 400);
+			result.put("msg", "mediaServerId is null");
+			return new ResponseEntity<String>( result.toJSONString(), HttpStatus.BAD_REQUEST);
 		}
-		return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
+		IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
+		if (mediaInfo == null) {
+			result.put("code", 0);
+			result.put("msg", "浣跨敤鐨勬祦濯掍綋宸茬粡鍋滄杩愯");
+			return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
+		}else {
+			JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(mediaInfo, key);
+			logger.info(jsonObject.toJSONString());
+			if (jsonObject != null && jsonObject.getInteger("code") == 0) {
+				result.put("code", 0);
+				JSONObject data = jsonObject.getJSONObject("data");
+				if (data != null && data.getBoolean("flag")) {
+					result.put("code", "0");
+					result.put("msg", "success");
+				}else {
+
+				}
+			}else {
+				result.put("code", 1);
+				result.put("msg", "delFFmpegSource fail");
+			}
+			return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
+		}
+
+
 	}
 
 	@ApiOperation("璇煶骞挎挱鍛戒护")
@@ -249,7 +271,7 @@
 			resultHolder.invokeResult(msg);
 			return result;
 		}
-		cmder.audioBroadcastCmd(device, event -> {
+		cmder.audioBroadcastCmd(device, (event) -> {
 			Response response = event.getResponse();
 			RequestMessage msg = new RequestMessage();
 			msg.setId(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId);
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
index 11c210e..d2a30fa 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
@@ -4,6 +4,8 @@
 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.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.service.IPlayService;
 import io.swagger.annotations.Api;
@@ -87,9 +89,18 @@
 			cmder.streamByeCmd(deviceId, channelId);
 		}
 		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
-		cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> {
+		IMediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
+		if (newMediaServerItem == null) {
+			logger.warn(String.format("璁惧鍥炴斁瓒呮椂锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId));
+			RequestMessage msg = new RequestMessage();
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
+			msg.setData("Timeout");
+			resultHolder.invokeResult(msg);
+			return result;
+		}
+		cmder.playbackStreamCmd(newMediaServerItem, device, channelId, startTime, endTime, (IMediaServerItem mediaServerItem, JSONObject response) -> {
 			logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
-			playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString());
+			playService.onPublishHandlerForPlayBack(mediaServerItem, response, deviceId, channelId, uuid.toString());
 		}, event -> {
 			Response response = event.getResponse();
 			RequestMessage msg = new RequestMessage();
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java
index 7e57e0d..f78b333 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java
@@ -9,6 +9,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
 
@@ -104,7 +105,7 @@
 		cmder.presetQuery(device, channelId, event -> {
 			Response response = event.getResponse();
 			RequestMessage msg = new RequestMessage();
-			msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
 			msg.setData(String.format("鑾峰彇璁惧棰勭疆浣嶅け璐ワ紝閿欒鐮侊細 %s, %s", response.getStatusCode(), response.getReasonPhrase()));
 			resultHolder.invokeResult(msg);
 		});
@@ -113,11 +114,11 @@
 			logger.warn(String.format("鑾峰彇璁惧棰勭疆浣嶈秴鏃�"));
 			// 閲婃斁rtpserver
 			RequestMessage msg = new RequestMessage();
-			msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (XmlUtil.isEmpty(channelId) ? deviceId : channelId));
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (StringUtils.isEmpty(channelId) ? deviceId : channelId));
 			msg.setData("鑾峰彇璁惧棰勭疆浣嶈秴鏃�");
 			resultHolder.invokeResult(msg);
 		});
-		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result);
+		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (StringUtils.isEmpty(channelId) ? deviceId : channelId), result);
 		return result;
 	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecoderProxyController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecoderProxyController.java
index 734f62f..f00e2ab 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecoderProxyController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecoderProxyController.java
@@ -2,6 +2,9 @@
 
 import com.genersoft.iot.vmp.conf.MediaConfig;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
@@ -27,6 +30,8 @@
 
     @Autowired
     private IRedisCatchStorage redisCatchStorage;
+    @Autowired
+    private IMediaServerService mediaServerService;
 
     @Autowired
     private MediaConfig mediaConfig;
@@ -48,7 +53,11 @@
             return null;
         }
         // 鍚庣画鏀逛负鏍规嵁Id鑾峰彇瀵瑰簲鐨刏LM
-        ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
+        IMediaServerItem mediaInfo = mediaServerService.getOne(mediaId);
+        if (mediaInfo == null) {
+            response.setStatus(HttpStatus.NOT_FOUND.value());
+            return null;
+        }
         String requestURI = String.format("http://%s:%s%s?%s",
                 mediaInfo.getSdpIp(),
                 mediaConfig.getRecordAssistPort(),
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 bbd4bd5..45eeac8 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
@@ -2,8 +2,11 @@
 
 import com.genersoft.iot.vmp.VManageBootstrap;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.utils.SpringBeanFactory;
+import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 import gov.nist.javax.sip.SipStackImpl;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -16,6 +19,7 @@
 import javax.sip.SipProvider;
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 
 @SuppressWarnings("rawtypes")
 @Api(tags = "鏈嶅姟鎺у埗")
@@ -28,17 +32,28 @@
     private ConfigurableApplicationContext context;
 
     @Autowired
-    private IRedisCatchStorage redisCatchStorage;
+    private IMediaServerService mediaServerService;
 
 
     @ApiOperation("娴佸獟浣撴湇鍔″垪琛�")
     @GetMapping(value = "/media_server/list")
     @ResponseBody
-    public Object getMediaServerList(){
-        // TODO 涓哄悗缁涓獄lm鏀寔鍑嗗
-        ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
-        ArrayList<ZLMServerConfig> result = new ArrayList<>();
-        result.add(mediaInfo);
+    public WVPResult<List<IMediaServerItem>> getMediaServerList(){
+        WVPResult<List<IMediaServerItem>> result = new WVPResult<>();
+        result.setCode(0);
+        result.setMsg("success");
+        result.setData(mediaServerService.getAll());
+        return result;
+    }
+
+    @ApiOperation("鑾峰彇娴佸獟浣撴湇鍔�")
+    @GetMapping(value = "/media_server/one/{id}")
+    @ResponseBody
+    public WVPResult<IMediaServerItem> getMediaServer(@PathVariable String id){
+        WVPResult<IMediaServerItem> result = new WVPResult<>();
+        result.setCode(0);
+        result.setMsg("success");
+        result.setData(mediaServerService.getOne(id));
         return result;
     }
 
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 51c8c8e..f099631 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
@@ -1,11 +1,15 @@
 package com.genersoft.iot.vmp.vmanager.streamProxy;
 
 import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
+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 com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.service.IStreamProxyService;
 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 import com.github.pagehelper.PageInfo;
+import io.netty.util.internal.StringUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
@@ -14,6 +18,7 @@
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 
 @SuppressWarnings("rawtypes")
@@ -30,6 +35,10 @@
 
     @Autowired
     private IRedisCatchStorage redisCatchStorage;
+
+
+    @Autowired
+    private IMediaServerService mediaServerService;
 
     @Autowired
     private IStreamProxyService streamProxyService;
@@ -60,6 +69,7 @@
     @ResponseBody
     public WVPResult save(@RequestBody StreamProxyItem param){
         logger.info("娣诲姞浠g悊锛� " + JSONObject.toJSONString(param));
+        if (StringUtils.isEmpty(param.getMediaServerId())) param.setMediaServerId("auto");
         String msg = streamProxyService.save(param);
         WVPResult<Object> result = new WVPResult<>();
         result.setCode(0);
@@ -69,10 +79,15 @@
 
     @ApiOperation("鑾峰彇ffmpeg.cmd妯℃澘")
     @GetMapping(value = "/ffmpeg_cmd/list")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "mediaServerId", value = "娴佸獟浣揑D", dataTypeClass = String.class),
+    })
     @ResponseBody
-    public WVPResult getFFmpegCMDs(){
-        logger.debug("鑾峰彇ffmpeg.cmd妯℃澘锛�" );
-        JSONObject data = streamProxyService.getFFmpegCMDs();
+    public WVPResult getFFmpegCMDs(@RequestParam String mediaServerId){
+        logger.debug("鑾峰彇鑺傜偣[ {} ]ffmpeg.cmd妯℃澘", mediaServerId );
+
+        IMediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
+        JSONObject data = streamProxyService.getFFmpegCMDs(mediaServerItem);
         WVPResult<JSONObject> result = new WVPResult<>();
         result.setCode(0);
         result.setMsg("success");
@@ -82,12 +97,12 @@
 
     @ApiOperation("绉婚櫎浠g悊")
     @ApiImplicitParams({
-            @ApiImplicitParam(name = "app", value = "搴旂敤鍚�", dataTypeClass = String.class),
-            @ApiImplicitParam(name = "stream", value = "娴両D", dataTypeClass = String.class),
+            @ApiImplicitParam(name = "app", value = "搴旂敤鍚�", required = true, dataTypeClass = String.class),
+            @ApiImplicitParam(name = "stream", value = "娴両D", required = true, dataTypeClass = String.class),
     })
     @DeleteMapping(value = "/del")
     @ResponseBody
-    public WVPResult del(String app, String stream){
+    public WVPResult del(@RequestParam String app, @RequestParam String stream){
         logger.info("绉婚櫎浠g悊锛� " + app + "/" + stream);
         WVPResult<Object> result = new WVPResult<>();
         if (app == null || stream == null) {
diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiControlController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiControlController.java
index c55824a..a8e0de4 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/ApiControlController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/ApiControlController.java
@@ -10,7 +10,7 @@
 import org.springframework.web.bind.annotation.*;
 
 /**
- * 鍏煎LiveGBS鐨凙PI锛氳澶囨帶鍒�
+ * API鍏煎锛氳澶囨帶鍒�
  */
 @CrossOrigin
 @RestController
diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiController.java
index 43ae7d9..8035810 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/ApiController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/ApiController.java
@@ -11,7 +11,7 @@
 import org.springframework.web.bind.annotation.ResponseBody;
 
 /**
- * 鍏煎LiveGBS鐨凙PI锛氱郴缁熸帴鍙�
+ * API鍏煎锛氱郴缁熸帴鍙�
  */
 @Controller
 @CrossOrigin
diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
index 09c94bd..264f2b2 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
@@ -14,7 +14,7 @@
 import java.util.List;
 
 /**
- * 鍏煎LiveGBS鐨凙PI锛氳澶囦俊鎭�
+ * API鍏煎锛氳澶囦俊鎭�
  */
 @SuppressWarnings("unchecked")
 @CrossOrigin
diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
index 932684a..ae7e921 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
@@ -17,7 +17,7 @@
 import org.springframework.web.context.request.async.DeferredResult;
 
 /**
- * 鍏煎LiveGBS鐨凙PI锛氬疄鏃剁洿鎾�
+ * API鍏煎锛氬疄鏃剁洿鎾�
  */
 @SuppressWarnings(value = {"rawtypes", "unchecked"})
 @CrossOrigin
diff --git a/src/main/resources/all-application.yml b/src/main/resources/all-application.yml
index 127cbcf..2552e01 100644
--- a/src/main/resources/all-application.yml
+++ b/src/main/resources/all-application.yml
@@ -70,9 +70,13 @@
     keepalive-timeout: 180
     # [鍙�塢 鍥芥爣绾ц仈娉ㄥ唽澶辫触锛屽啀娆″彂璧锋敞鍐岀殑鏃堕棿闂撮殧銆� 榛樿60绉�
     register-time-interval: 60
+    # TODO [鍙�塢 鏀跺埌蹇冭烦鍚庤嚜鍔ㄤ笂绾匡紝 閲嶅惎鏈嶅姟鍚庝細灏嗘墍鏈夎澶囩疆涓虹绾匡紝榛樿false锛岀瓑寰呮敞鍐屽悗涓婄嚎銆傝缃负true鍒欐敹鍒板績璺宠缃负涓婄嚎銆�
+    # keepalliveToOnline: false
 
 #zlm 榛樿鏈嶅姟鍣ㄩ厤缃�
 media:
+    # [鍙�塢 zlm鏈嶅姟鍣ㄥ敮涓�id锛岀敤浜庤Е鍙慼ook鏃跺尯鍒槸鍝彴鏈嶅姟鍣�,general.mediaServerId
+    id:
     # [蹇呴』淇敼] zlm鏈嶅姟鍣ㄧ殑鍐呯綉IP
     ip: 192.168.0.100
     # [鍙�塢 杩斿洖娴佸湴鍧�鏃剁殑ip锛岀疆绌轰娇鐢� media.ip
diff --git a/src/main/resources/wvp.sqlite b/src/main/resources/wvp.sqlite
index 7c38c43..f399e6e 100644
--- a/src/main/resources/wvp.sqlite
+++ b/src/main/resources/wvp.sqlite
Binary files differ
diff --git a/web_src/src/components/CloudRecord.vue b/web_src/src/components/CloudRecord.vue
index c269270..284578b 100644
--- a/web_src/src/components/CloudRecord.vue
+++ b/web_src/src/components/CloudRecord.vue
@@ -7,22 +7,23 @@
 			<el-main>
         <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
           <span style="font-size: 1rem; font-weight: bold;">浜戠褰曞儚</span>
+          <div style="position: absolute; right: 5rem; top: 0.3rem;">
+            鑺傜偣閫夋嫨: <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServer" placeholder="璇烽�夋嫨" default-first-option>
+            <el-option
+              v-for="item in mediaServerList"
+              :key="item.id"
+              :label="item.id + '( ' + item.streamIp + ' )'"
+              :value="item">
+            </el-option>
+          </el-select>
+          </div>
           <div style="position: absolute; right: 1rem; top: 0.3rem;">
             <el-button v-if="!recordDetail" icon="el-icon-refresh-right" circle size="mini" :loading="loading" @click="getRecordList()"></el-button>
             <el-button v-if="recordDetail" icon="el-icon-arrow-left" circle size="mini" @click="backToList()"></el-button>
           </div>
         </div>
         <div v-if="!recordDetail">
-          <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;">
-            鑺傜偣閫夋嫨: <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServer" placeholder="璇烽�夋嫨" default-first-option>
-            <el-option
-              v-for="item in mediaServerList"
-              :key="item.generalMediaServerId"
-              :label="item.generalMediaServerId + '( ' + item.wanIp + ' )'"
-              :value="item">
-            </el-option>
-          </el-select>
-          </div>
+
           <!--璁惧鍒楄〃-->
           <el-table :data="recordList" border style="width: 100%" :height="winHeight">
             <el-table-column prop="app" label="搴旂敤鍚�" align="center">
@@ -60,6 +61,7 @@
 <script>
 	import uiHeader from './UiHeader.vue'
 	import cloudRecordDetail from './CloudRecordDetail.vue'
+  import MediaServer from './service/MediaServer'
 	export default {
 		name: 'app',
 		components: {
@@ -78,6 +80,7 @@
         count:15,
         total:0,
         loading: false,
+        mediaServerObj : new MediaServer(),
         recordDetail: false
 
 			};
@@ -107,20 +110,13 @@
       },
       getMediaServerList: function (){
         let that = this;
-        this.$axios({
-          method: 'get',
-          url:`/api/server/media_server/list`,
-        }).then(function (res) {
-          console.log(res)
-          that.mediaServerList = res.data;
+        that.mediaServerObj.getMediaServerList((data)=>{
+          that.mediaServerList = data;
           if (that.mediaServerList.length > 0) {
             that.mediaServer = that.mediaServerList[0]
             that.getRecordList();
           }
-
-        }).catch(function (error) {
-          console.log(error);
-        });
+        })
       },
       getRecordList: function (){
         let that = this;
diff --git a/web_src/src/components/PushVideoList.vue b/web_src/src/components/PushVideoList.vue
index f40fe3c..bdc086c 100644
--- a/web_src/src/components/PushVideoList.vue
+++ b/web_src/src/components/PushVideoList.vue
@@ -17,6 +17,8 @@
 					</el-table-column>
 					<el-table-column prop="gbId" label="鍥芥爣缂栫爜" width="150" align="center">
 					</el-table-column>
+					<el-table-column prop="mediaServerId" label="娴佸獟浣�" width="150" align="center">
+					</el-table-column>
 					<el-table-column label="寮�濮嬫椂闂�" align="center" >
 						<template slot-scope="scope">
 							<el-button-group>
@@ -29,7 +31,7 @@
 							{{(scope.row.status == false && scope.row.gbId == null) || scope.row.status ?'鏄�':'鍚�'}}
 						</template>
 					</el-table-column>
-					
+
 					<el-table-column label="鎿嶄綔" width="360" align="center" fixed="right">
 						<template slot-scope="scope">
 							<el-button-group>
@@ -125,7 +127,7 @@
 					that.getDeviceListLoading = false;
 				});
 			},
-			
+
 			playPuhsh: function(row){
 				let that = this;
 				this.getListLoading = true;
@@ -134,7 +136,8 @@
 					url:`/api/media/stream_info_by_app_and_stream`,
 					params: {
 						app: row.app,
-						stream: row.stream
+						stream: row.stream,
+            mediaServerId: row.mediaServerId
 					}
 				}).then(function (res) {
 					that.getListLoading = false;
diff --git a/web_src/src/components/StreamProxyList.vue b/web_src/src/components/StreamProxyList.vue
index 90425b5..45fd573 100644
--- a/web_src/src/components/StreamProxyList.vue
+++ b/web_src/src/components/StreamProxyList.vue
@@ -32,6 +32,15 @@
 						</div>
 						</template>
 					</el-table-column>
+          <el-table-column prop="mediaServerId" label="娴佸獟浣�" width="150" align="center"></el-table-column>
+          <el-table-column label="绫诲瀷" width="100" align="center">
+            <template slot-scope="scope">
+              <div slot="reference" class="name-wrapper">
+                <el-tag size="medium">{{scope.row.type}}</el-tag>
+              </div>
+            </template>
+          </el-table-column>
+
 					<el-table-column prop="gbId" label="鍥芥爣缂栫爜" width="180" align="center" show-overflow-tooltip/>
           <el-table-column label="鍚敤" width="120" align="center">
             <template slot-scope="scope">
@@ -147,8 +156,6 @@
 						count: that.count
 					}
 				}).then(function (res) {
-					console.log(res);
-					console.log(res.data.list);
 					that.total = res.data.total;
 					that.streamProxyList = res.data.list;
 					that.getListLoading = false;
@@ -170,7 +177,6 @@
           this.getListLoading = false;
           if (res.data.code == 0 ){
             if (res.data.data.length > 0) {
-              console.log(res.data.data)
               this.$refs.onvifEdit.openDialog(res.data.data, (url)=>{
                   if (url != null) {
                     this.$refs.onvifEdit.close();
@@ -200,7 +206,8 @@
 					url:`/api/media/stream_info_by_app_and_stream`,
 					params: {
 						app: row.app,
-						stream: row.stream
+						stream: row.stream,
+            mediaServerId: row.mediaServerId
 					}
 				}).then(function (res) {
 					that.getListLoading = false;
diff --git a/web_src/src/components/control.vue b/web_src/src/components/control.vue
index 51bcb0a..b8b0efc 100644
--- a/web_src/src/components/control.vue
+++ b/web_src/src/components/control.vue
@@ -7,6 +7,17 @@
         <el-main>
             <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
                 <span style="font-size: 1rem; font-weight: bold;">鎺у埗鍙�</span>
+                <div style="position: absolute; right: 17rem; top: 0.3rem;">
+                  鑺傜偣閫夋嫨: <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServerChoose" placeholder="璇烽�夋嫨" default-first-option>
+                  <el-option
+                    v-for="item in mediaServerList"
+                    :key="item.id"
+                    :label="item.id + '( ' + item.streamIp + ' )'"
+                    :value="item.id">
+                  </el-option>
+                  </el-select>
+                  <span >{{loadCount}}</span>
+                </div>
                 <div style="position: absolute; right: 1rem; top: 0.3rem;">
                     <el-popover placement="bottom" width="750" height="300" trigger="click">
                         <div style="height: 600px;overflow:auto;">
@@ -53,6 +64,7 @@
 
 <script>
 import uiHeader from './UiHeader.vue'
+import MediaServer from './service/MediaServer'
 
 import echarts from 'echarts';
 export default {
@@ -87,68 +99,101 @@
             chartInterval: 0, //鏇存柊鍥捐〃缁熻鍥惧畾鏃朵换鍔℃爣璇�
             allSessionData: [],
             visible: false,
-            serverConfig: {}
+            serverConfig: {},
+            mediaServer : new MediaServer(),
+            mediaServerChoose : null,
+            loadCount : 0,
+            mediaServerList : []
         };
     },
     mounted() {
-        this.getAllSession();
+
         this.initTable();
         this.updateData();
         this.chartInterval = setInterval(this.updateData, 3000);
+        this.mediaServer.getMediaServerList((data)=>{
+          this.mediaServerList = data.data;
+          if (this.mediaServerList && this.mediaServerList.length > 0) {
+            this.mediaServerChoose = this.mediaServerList[0].id
+            this.loadCount = this.mediaServerList[0].count;
+            this.getThreadsLoad();
+            this.getAllSession();
+          }
+        })
     },
     destroyed() {
         clearInterval(this.chartInterval); //閲婃斁瀹氭椂浠诲姟
     },
     methods: {
+        chooseMediaChange: function (val) {
+            this.loadCount = 0
+            this.initTable()
+            this.updateData();
+        },
         updateData: function () {
             this.getThreadsLoad();
+            this.getLoadCount();
+            this.getAllSession();
         },
         /**
          * 鑾峰彇绾跨▼鐘舵��
          */
         getThreadsLoad: function () {
             let that = this;
-            this.$axios({
+            if (that.mediaServerChoose != null) {
+              this.$axios({
                 method: 'get',
-                url: '/zlm/index/api/getThreadsLoad'
-            }).then(function (res) {
+                url: '/zlm/' + that.mediaServerChoose +'/index/api/getThreadsLoad'
+              }).then(function (res) {
                 if (res.data.code == 0) {
-                    that.tableOption.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
-                        hour12: false
-                    }));
-                    that.table1Option.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
-                        hour12: false
-                    }));
+                  that.tableOption.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
+                    hour12: false
+                  }));
+                  that.table1Option.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
+                    hour12: false
+                  }));
 
-                    for (var i = 0; i < res.data.data.length; i++) {
-                        if (that.tableOption.series[i] === undefined) {
-                            let data = {
-                                data: [],
-                                type: 'line'
-                            };
-                            let data1 = {
-                                data: [],
-                                type: 'line'
-                            };
-                            data.data.push(res.data.data[i].delay);
-                            data1.data.push(res.data.data[i].load);
-                            that.tableOption.series.push(data);
-                            that.table1Option.series.push(data1);
-                        } else {
-                            that.tableOption.series[i].data.push(res.data.data[i].delay);
-                            that.table1Option.series[i].data.push(res.data.data[i].load);
-                        }
+                  for (var i = 0; i < res.data.data.length; i++) {
+                    if (that.tableOption.series[i] === undefined) {
+                      let data = {
+                        data: [],
+                        type: 'line'
+                      };
+                      let data1 = {
+                        data: [],
+                        type: 'line'
+                      };
+                      data.data.push(res.data.data[i].delay);
+                      data1.data.push(res.data.data[i].load);
+                      that.tableOption.series.push(data);
+                      that.table1Option.series.push(data1);
+                    } else {
+                      that.tableOption.series[i].data.push(res.data.data[i].delay);
+                      that.table1Option.series[i].data.push(res.data.data[i].load);
                     }
-                    that.tableOption.dataZoom[0].start = that.charZoomStart;
-                    that.tableOption.dataZoom[0].end = that.charZoomEnd;
-                    that.table1Option.dataZoom[0].start = that.charZoomStart;
-                    that.table1Option.dataZoom[0].end = that.charZoomEnd;
-                    //that.myChart = echarts.init(document.getElementById('ThreadsLoad'));
-                    that.myChart.setOption(that.tableOption, true);
-                    // that.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
-                    that.myChart1.setOption(that.table1Option, true);
+                  }
+                  that.tableOption.dataZoom[0].start = that.charZoomStart;
+                  that.tableOption.dataZoom[0].end = that.charZoomEnd;
+                  that.table1Option.dataZoom[0].start = that.charZoomStart;
+                  that.table1Option.dataZoom[0].end = that.charZoomEnd;
+                  //that.myChart = echarts.init(document.getElementById('ThreadsLoad'));
+                  that.myChart.setOption(that.tableOption, true);
+                  // that.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
+                  that.myChart1.setOption(that.table1Option, true);
                 }
-            });
+              });
+            }
+
+        },
+        getLoadCount: function (){
+          let that = this;
+          if (that.mediaServerChoose != null) {
+            that.mediaServer.getMediaServer(that.mediaServerChoose, (data)=>{
+              if (data.code == 0) {
+                that.loadCount = data.data.count
+              }
+            })
+          }
         },
         initTable: function () {
             let that = this;
@@ -242,10 +287,9 @@
         getAllSession: function () {
             let that = this;
             that.allSessionData = [];
-            console.log("鍦板潃锛�" + '/zlm/index/api/getAllSession');
             this.$axios({
                 method: 'get',
-                url: '/zlm/index/api/getAllSession'
+                url: '/zlm/' + that.mediaServerChoose +'/index/api/getAllSession'
             }).then(function (res) {
                 res.data.data.forEach(item => {
                     let data = {
diff --git a/web_src/src/components/dialog/StreamProxyEdit.vue b/web_src/src/components/dialog/StreamProxyEdit.vue
index e1d224a..3310d9c 100644
--- a/web_src/src/components/dialog/StreamProxyEdit.vue
+++ b/web_src/src/components/dialog/StreamProxyEdit.vue
@@ -39,6 +39,22 @@
               <el-form-item label="瓒呮椂鏃堕棿:姣" prop="timeout_ms" v-if="proxyParam.type=='ffmpeg'">
                 <el-input v-model="proxyParam.timeout_ms" clearable></el-input>
               </el-form-item>
+              <el-form-item label="鑺傜偣閫夋嫨" prop="rtp_type">
+                <el-select
+                  v-model="proxyParam.mediaServerId"
+                  @change="mediaServerIdChange"
+                  style="width: 100%"
+                  placeholder="璇烽�夋嫨鎷夋祦鑺傜偣"
+                >
+                  <el-option label="鑷姩閫夋嫨" value="auto"></el-option>
+                  <el-option
+                    v-for="item in mediaServerList"
+                    :key="item.id"
+                    :label="item.id"
+                    :value="item.id">
+                  </el-option>
+                </el-select>
+              </el-form-item>
               <el-form-item label="FFmpeg鍛戒护妯℃澘" prop="ffmpeg_cmd_key" v-if="proxyParam.type=='ffmpeg'">
 <!--                <el-input v-model="proxyParam.ffmpeg_cmd_key" clearable></el-input>-->
                 <el-select
@@ -68,6 +84,7 @@
                   <el-option label="缁勬挱" value="2"></el-option>
                 </el-select>
               </el-form-item>
+
               <el-form-item label="鍥芥爣骞冲彴">
                 <el-select
                   v-model="proxyParam.platformGbId"
@@ -106,6 +123,8 @@
 </template>
 
 <script>
+import MediaServer from './../service/MediaServer'
+
 export default {
   name: "streamProxyEdit",
   props: {},
@@ -134,27 +153,8 @@
       isLoging: false,
       dialogLoading: false,
       onSubmit_text: "绔嬪嵆鍒涘缓",
-      platformList: [{
-          id: 1,
-          enable: true,
-          name: "141",
-          serverGBId: "34020000002000000001",
-          serverGBDomain: "3402000000",
-          serverIP: "192.168.1.141",
-          serverPort: 15060,
-          deviceGBId: "34020000002000000001",
-          deviceIp: "192.168.1.20",
-          devicePort: "5060",
-          username: "34020000002000000001",
-          password: "12345678",
-          expires: "300",
-          keepTimeout: "60",
-          transport: "UDP",
-          characterSet: "GB2312",
-          ptz: false,
-          rtcp: false,
-          status: true,
-      }],
+      platformList: [],
+      mediaServer: new MediaServer(),
       proxyParam: {
           name: null,
           type: "default",
@@ -170,7 +170,9 @@
           enable_hls: true,
           enable_mp4: false,
           platformGbId: null,
+          mediaServerId: "auto",
       },
+      mediaServerList:{},
       ffmpegCmdList:{},
 
       rules: {
@@ -193,7 +195,6 @@
       }
 
       let that = this;
-
       this.$axios({
         method: 'get',
         url:`/api/platform/query/10000/0`
@@ -202,17 +203,28 @@
       }).catch(function (error) {
         console.log(error);
       });
-      this.$axios({
-        method: 'get',
-        url:`/api/proxy/ffmpeg_cmd/list`
-      }).then(function (res) {
-        that.ffmpegCmdList = res.data.data;
-      }).catch(function (error) {
-        console.log(error);
-      });
+      this.mediaServer.getMediaServerList((data)=>{
+        this.mediaServerList = data;
+      })
+    },
+    mediaServerIdChange:function (){
+      let that = this;
+      if (that.proxyParam.mediaServerId !== "auto"){
+        that.$axios({
+          method: 'get',
+          url:`/api/proxy/ffmpeg_cmd/list`,
+          params: {
+            mediaServerId: that.proxyParam.mediaServerId
+          }
+        }).then(function (res) {
+          that.ffmpegCmdList = res.data.data;
+        }).catch(function (error) {
+          console.log(error);
+        });
+      }
+
     },
     onSubmit: function () {
-      console.log("onSubmit");
       this.dialogLoading = true;
       var that = this;
       that.$axios({
@@ -239,7 +251,6 @@
       });
     },
     close: function () {
-      console.log("鍏抽棴娣诲姞瑙嗛骞冲彴");
       this.showDialog = false;
       this.dialogLoading = false;
       this.$refs.streamProxy.resetFields();
diff --git a/web_src/src/components/dialog/devicePlayer.vue b/web_src/src/components/dialog/devicePlayer.vue
index b7187b7..020cc22 100644
--- a/web_src/src/components/dialog/devicePlayer.vue
+++ b/web_src/src/components/dialog/devicePlayer.vue
@@ -181,6 +181,7 @@
             showVideoDialog: false,
             streamId: '',
             app : '',
+            mediaServerId : '',
             convertKey: '',
             deviceId: '',
             channelId: '',
@@ -218,7 +219,7 @@
             if (tab.name == "codec") {
                 this.$axios({
                     method: 'get',
-                    url: '/zlm/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId
+                    url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId
                 }).then(function (res) {
                     that.tracksLoading = false;
                     if (res.data.code == 0 && res.data.online) {
@@ -235,12 +236,11 @@
             }
         },
         openDialog: function (tab, deviceId, channelId, param) {
-          console.log("openDialog")
-          console.log(param)
             this.tabActiveName = tab;
             this.channelId = channelId;
             this.deviceId = deviceId;
             this.streamId = "";
+            this.mediaServerId = "";
             this.app = "";
             this.videoUrl = ""
             if (!!this.$refs.videoPlayer) {
@@ -257,8 +257,8 @@
                     break;
                 case "streamPlay":
                     this.tabActiveName = "media";
-                    this.showRrecord = false,
-                    this.showPtz = false,
+                    this.showRrecord = false;
+                    this.showPtz = false;
                     this.play(param.streamInfo, param.hasAudio)
                     break;
                 case "control":
@@ -269,19 +269,17 @@
             console.log(val)
         },
         play: function (streamInfo, hasAudio) {
-
             this.hasAudio = hasAudio;
             this.isLoging = false;
             // this.videoUrl = streamInfo.rtc;
             this.videoUrl = this.getUrlByStreamInfo(streamInfo);
             this.streamId = streamInfo.streamId;
             this.app = streamInfo.app;
+            this.mediaServerId = streamInfo.mediaServerId;
             this.playFromStreamInfo(false, streamInfo)
         },
         getUrlByStreamInfo(streamInfo){
             let baseZlmApi = process.env.NODE_ENV === 'development'?`${location.host}/debug/zlm`:`${location.host}/zlm`
-            console.log(12121212)
-            console.log(baseZlmApi)
             // return `${baseZlmApi}/${streamInfo.app}/${streamInfo.streamId}.flv`;
             // return `http://${baseZlmApi}/${streamInfo.app}/${streamInfo.streamId}.flv`;
             return streamInfo.ws_flv;
@@ -430,6 +428,7 @@
                     var streamInfo = res.data;
                     that.app = streamInfo.app;
                     that.streamId = streamInfo.streamId;
+                    that.mediaServerId = streamInfo.mediaServerId;
                     that.videoUrl = that.getUrlByStreamInfo(streamInfo);
                     that.recordPlay = true;
                 });
diff --git a/web_src/src/components/service/MediaServer.js b/web_src/src/components/service/MediaServer.js
new file mode 100644
index 0000000..a63d19c
--- /dev/null
+++ b/web_src/src/components/service/MediaServer.js
@@ -0,0 +1,32 @@
+import axios from 'axios';
+
+class MediaServer{
+
+  constructor() {
+    this.$axios = axios;
+  }
+
+  getMediaServerList(callback){
+    this.$axios({
+      method: 'get',
+      url:`/api/server/media_server/list`,
+    }).then(function (res) {
+      if (typeof (callback) == "function") callback(res.data)
+    }).catch(function (error) {
+      console.log(error);
+    });
+  }
+
+  getMediaServer(id, callback){
+    this.$axios({
+      method: 'get',
+      url:`/api/server/media_server/one/` + id,
+    }).then(function (res) {
+      if (typeof (callback) == "function") callback(res.data)
+    }).catch(function (error) {
+      console.log(error);
+    });
+  }
+}
+
+export default MediaServer;

--
Gitblit v1.8.0