From 44d216100b45c3337c593ee82ee68e7e0f35d24b Mon Sep 17 00:00:00 2001
From: Lawrence <1934378145@qq.com>
Date: 星期三, 16 十二月 2020 20:29:19 +0800
Subject: [PATCH] 与master分支同步

---
 src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java              |    2 
 src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java                          |  137 ++---
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java                |  119 +++--
 src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java                                     |   56 ++
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java     |    6 
 src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java          |    4 
 web_src/package-lock.json                                                                      |    8 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java                    |   51 +-
 web_src/index.html                                                                             |    2 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java                        |   90 ++++
 src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java                 |   90 ++++
 src/main/resources/application-dev.yml                                                         |   94 ++++
 web_src/build/webpack.dev.conf.js                                                              |    5 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java                                   |   17 
 web_src/src/components/gb28181/player.vue                                                      |   57 ++
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java     |   34 +
 web_src/src/components/videoList.vue                                                           |    2 
 src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java                         |   13 
 web_src/src/components/gb28181/devicePlayer.vue                                                |  222 ++++++---
 web_src/package.json                                                                           |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java        |    2 
 src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java                  |  117 +---
 src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java                               |    7 
 web_src/build/webpack.prod.conf.js                                                             |    5 
 src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java                                      |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java             |    6 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java                         |   57 +-
 web_src/src/router/index.js                                                                    |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java |    5 
 src/main/resources/application.yml                                                             |   65 --
 30 files changed, 829 insertions(+), 450 deletions(-)

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 1dd3a85..53bda91 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -5,12 +5,18 @@
 public class StreamInfo {
 
     private String ssrc;
+    private String streamId;
     private String deviceID;
     private String cahnnelId;
     private String flv;
     private String ws_flv;
-    private String rtmp;
+    private String fmp4;
+    private String ws_fmp4;
     private String hls;
+    private String ws_hls;
+    private String ts;
+    private String ws_ts;
+    private String rtmp;
     private String rtsp;
     private JSONArray tracks;
 
@@ -85,4 +91,52 @@
     public void setTracks(JSONArray tracks) {
         this.tracks = tracks;
     }
+
+    public String getFmp4() {
+        return fmp4;
+    }
+
+    public void setFmp4(String fmp4) {
+        this.fmp4 = fmp4;
+    }
+
+    public String getWs_fmp4() {
+        return ws_fmp4;
+    }
+
+    public void setWs_fmp4(String ws_fmp4) {
+        this.ws_fmp4 = ws_fmp4;
+    }
+
+    public String getWs_hls() {
+        return ws_hls;
+    }
+
+    public void setWs_hls(String ws_hls) {
+        this.ws_hls = ws_hls;
+    }
+
+    public String getTs() {
+        return ts;
+    }
+
+    public void setTs(String ts) {
+        this.ts = ts;
+    }
+
+    public String getWs_ts() {
+        return ws_ts;
+    }
+
+    public void setWs_ts(String ws_ts) {
+        this.ws_ts = ws_ts;
+    }
+
+    public String getStreamId() {
+        return streamId;
+    }
+
+    public void setStreamId(String streamId) {
+        this.streamId = streamId;
+    }
 }
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 9b091e6..54c0711 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -113,6 +113,7 @@
 	 */
 	@Override
 	public void processRequest(RequestEvent evt) {
+		logger.debug(evt.getRequest().toString());
 		// 鐢变簬jainsip鏄崟绾跨▼绋嬪簭锛屼负鎻愰珮鎬ц兘骞跺彂澶勭悊
 		processThreadPool.execute(() -> {
 			processorFactory.createRequestProcessor(evt).process();
@@ -122,6 +123,7 @@
 	@Override
 	public void processResponse(ResponseEvent evt) {
 		Response response = evt.getResponse();
+		logger.debug(evt.getResponse().toString());
 		int status = response.getStatusCode();
 		if (((status >= 200) && (status < 300)) || status == 401) { // Success!
 			ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
index ec7ff88..b9bb5b1 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
@@ -32,7 +32,7 @@
 	public void onApplicationEvent(OnlineEvent event) {
 		
 		if (logger.isDebugEnabled()) {
-			logger.debug("璁惧绂荤嚎浜嬩欢瑙﹀彂锛宒eviceId锛�" + event.getDeviceId() + ",from:" + event.getFrom());
+			logger.debug("璁惧涓婄嚎浜嬩欢瑙﹀彂锛宒eviceId锛�" + event.getDeviceId() + ",from:" + event.getFrom());
 		}
 		
 		String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + event.getDeviceId();
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
index 4a4a538..c69faf9 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
@@ -17,13 +17,11 @@
 	private ConcurrentHashMap<String, ClientTransaction> sessionMap = new ConcurrentHashMap<>();
 
 	public String createPlaySsrc(){
-		String ssrc = SsrcUtil.getPlaySsrc();
-		return ssrc;
+		return SsrcUtil.getPlaySsrc();
 	}
 	
 	public String createPlayBackSsrc(){
-		String ssrc = SsrcUtil.getPlayBackSsrc();
-		return ssrc;
+		return SsrcUtil.getPlayBackSsrc();
 	}
 	
 	public void put(String ssrc,ClientTransaction transaction){
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
index 7c5cbc1..0c1e63d 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
@@ -22,6 +22,8 @@
 	
 	public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO";
 
+	public static final String CALLBACK_CMD_PlAY = "CALLBACK_PLAY";
+
 	private Map<String, DeferredResult> map = new HashMap<String, DeferredResult>();
 	
 	public void put(String key, DeferredResult result) {
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 32cc06e..d3f36cd 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
@@ -2,6 +2,7 @@
 
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 
 /**    
@@ -20,7 +21,7 @@
      * @param upDown     闀滃ご涓婄Щ涓嬬Щ 0:鍋滄 1:涓婄Щ 2:涓嬬Щ
      * @param moveSpeed  闀滃ご绉诲姩閫熷害
 	 */
-	public boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown);
+	boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown);
 	
 	/**
 	 * 浜戝彴鏂瑰悜鏀炬帶鍒�
@@ -31,7 +32,7 @@
      * @param upDown     闀滃ご涓婄Щ涓嬬Щ 0:鍋滄 1:涓婄Щ 2:涓嬬Щ
      * @param moveSpeed  闀滃ご绉诲姩閫熷害
 	 */
-	public boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed);
+	boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed);
 	
 	/**
 	 * 浜戝彴缂╂斁鎺у埗锛屼娇鐢ㄩ厤缃枃浠朵腑鐨勯粯璁ら暅澶寸缉鏀鹃�熷害
@@ -40,7 +41,7 @@
 	 * @param channelId  棰勮閫氶亾
      * @param inOut      闀滃ご鏀惧ぇ缂╁皬 0:鍋滄 1:缂╁皬 2:鏀惧ぇ
 	 */
-	public boolean ptzZoomCmd(Device device,String channelId,int inOut);
+	boolean ptzZoomCmd(Device device,String channelId,int inOut);
 	
 	/**
 	 * 浜戝彴缂╂斁鎺у埗
@@ -50,7 +51,7 @@
      * @param inOut      闀滃ご鏀惧ぇ缂╁皬 0:鍋滄 1:缂╁皬 2:鏀惧ぇ
      * @param zoomSpeed  闀滃ご缂╂斁閫熷害
 	 */
-	public boolean ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed);
+	boolean ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed);
 	
 	/**
 	 * 浜戝彴鎺у埗锛屾敮鎸佹柟鍚戜笌缂╂斁鎺у埗
@@ -63,7 +64,7 @@
      * @param moveSpeed  闀滃ご绉诲姩閫熷害
      * @param zoomSpeed  闀滃ご缂╂斁閫熷害
 	 */
-	public boolean ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed);
+	boolean ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed);
 	
 	/**
 	 * 鍓嶇鎺у埗锛屽寘鎷琍TZ鎸囦护銆丗I鎸囦护銆侀缃綅鎸囦护銆佸贰鑸寚浠ゃ�佹壂鎻忔寚浠ゅ拰杈呭姪寮�鍏虫寚浠�
@@ -75,7 +76,7 @@
      * @param parameter2	鏁版嵁2
      * @param combineCode2	缁勫悎鐮�2
 	 */
-	public boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2);
+	boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2);
 	
 	/**
 	 * 璇锋眰棰勮瑙嗛娴�
@@ -83,7 +84,7 @@
 	 * @param device  瑙嗛璁惧
 	 * @param channelId  棰勮閫氶亾
 	 */
-	public StreamInfo playStreamCmd(Device device, String channelId);
+	void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event);
 	
 	/**
 	 * 璇锋眰鍥炴斁瑙嗛娴�
@@ -93,14 +94,14 @@
 	 * @param startTime 寮�濮嬫椂闂�,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 */
-	public StreamInfo playbackStreamCmd(Device device,String channelId, String startTime, String endTime);
+	void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event);
 	
 	/**
 	 * 瑙嗛娴佸仠姝�
 	 * 
 	 * @param ssrc  ssrc
 	 */
-	public void streamByeCmd(String ssrc);
+	void streamByeCmd(String ssrc);
 	
 	/**
 	 * 璇煶骞挎挱
@@ -108,7 +109,7 @@
 	 * @param device  瑙嗛璁惧
 	 * @param channelId  棰勮閫氶亾
 	 */
-	public boolean audioBroadcastCmd(Device device,String channelId);
+	boolean audioBroadcastCmd(Device device,String channelId);
 	
 	/**
 	 * 闊宠棰戝綍鍍忔帶鍒�
@@ -116,21 +117,21 @@
 	 * @param device  瑙嗛璁惧
 	 * @param channelId  棰勮閫氶亾
 	 */
-	public boolean recordCmd(Device device,String channelId);
+	boolean recordCmd(Device device,String channelId);
 	
 	/**
 	 * 鎶ヨ甯冮槻/鎾ら槻鍛戒护
 	 * 
 	 * @param device  瑙嗛璁惧
 	 */
-	public boolean guardCmd(Device device);
+	boolean guardCmd(Device device);
 	
 	/**
 	 * 鎶ヨ澶嶄綅鍛戒护
 	 * 
 	 * @param device  瑙嗛璁惧
 	 */
-	public boolean alarmCmd(Device device);
+	boolean alarmCmd(Device device);
 	
 	/**
 	 * 寮哄埗鍏抽敭甯у懡浠�,璁惧鏀跺埌姝ゅ懡浠ゅ簲绔嬪埢鍙戦�佷竴涓狪DR甯�
@@ -138,21 +139,21 @@
 	 * @param device  瑙嗛璁惧
 	 * @param channelId  棰勮閫氶亾
 	 */
-	public boolean iFameCmd(Device device,String channelId);
+	boolean iFameCmd(Device device,String channelId);
 	
 	/**
 	 * 鐪嬪畧浣嶆帶鍒跺懡浠�
 	 * 
 	 * @param device  瑙嗛璁惧
 	 */
-	public boolean homePositionCmd(Device device);
+	boolean homePositionCmd(Device device);
 	
 	/**
 	 * 璁惧閰嶇疆鍛戒护
 	 * 
 	 * @param device  瑙嗛璁惧
 	 */
-	public boolean deviceConfigCmd(Device device);
+	boolean deviceConfigCmd(Device device);
 	
 	
 	/**
@@ -160,7 +161,7 @@
 	 * 
 	 * @param device 瑙嗛璁惧
 	 */
-	public boolean deviceStatusQuery(Device device);
+	boolean deviceStatusQuery(Device device);
 	
 	/**
 	 * 鏌ヨ璁惧淇℃伅
@@ -168,14 +169,14 @@
 	 * @param device 瑙嗛璁惧
 	 * @return 
 	 */
-	public boolean deviceInfoQuery(Device device);
+	boolean deviceInfoQuery(Device device);
 	
 	/**
 	 * 鏌ヨ鐩綍鍒楄〃
 	 * 
 	 * @param device 瑙嗛璁惧
 	 */
-	public boolean catalogQuery(Device device);
+	boolean catalogQuery(Device device);
 	
 	/**
 	 * 鏌ヨ褰曞儚淇℃伅
@@ -184,35 +185,33 @@
 	 * @param startTime 寮�濮嬫椂闂�,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 */
-	public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime);
+	boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime);
 	
 	/**
 	 * 鏌ヨ鎶ヨ淇℃伅
 	 * 
 	 * @param device 瑙嗛璁惧
 	 */
-	public boolean alarmInfoQuery(Device device);
+	boolean alarmInfoQuery(Device device);
 	
 	/**
 	 * 鏌ヨ璁惧閰嶇疆
 	 * 
 	 * @param device 瑙嗛璁惧
 	 */
-	public boolean configQuery(Device device);
+	boolean configQuery(Device device);
 	
 	/**
 	 * 鏌ヨ璁惧棰勭疆浣嶇疆
 	 * 
 	 * @param device 瑙嗛璁惧
 	 */
-	public boolean presetQuery(Device device);
+	boolean presetQuery(Device device);
 	
 	/**
 	 * 鏌ヨ绉诲姩璁惧浣嶇疆鏁版嵁
 	 * 
 	 * @param device 瑙嗛璁惧
 	 */
-	public boolean mobilePostitionQuery(Device device);
-
-
+	boolean mobilePostitionQuery(Device device);
 }
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 42657a6..3d5aacc 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
@@ -19,6 +19,7 @@
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.MediaServerConfig;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
 import com.genersoft.iot.vmp.media.zlm.ZLMUtils;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -66,6 +67,9 @@
 
 	@Value("${media.rtp.enable}")
 	private boolean rtpEnable;
+
+	@Autowired
+	private ZLMHttpHookSubscribe subscribe;
 
 
 
@@ -264,12 +268,12 @@
 	}
 	/**
 	 * 璇锋眰棰勮瑙嗛娴�
-	 * 
+	 *
 	 * @param device  瑙嗛璁惧
 	 * @param channelId  棰勮閫氶亾
-	 */  
+	 */
 	@Override
-	public StreamInfo playStreamCmd(Device device, String channelId) {
+	public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event) {
 		try {
 
 			String ssrc = streamSession.createPlaySsrc();
@@ -282,53 +286,63 @@
 			}else {
 				mediaPort = mediaInfo.getRtpProxyPort();
 			}
+
+			String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
+			// 娣诲姞璁㈤槄
+			JSONObject subscribeKey = new JSONObject();
+			subscribeKey.put("app", "rtp");
+			subscribeKey.put("id", streamId);
+
+			subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, subscribeKey, event);
 			//
 			StringBuffer content = new StringBuffer(200);
-	        content.append("v=0\r\n");
-	        content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
-	        content.append("s=Play\r\n");
-	        content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n");
-	        content.append("t=0 0\r\n");
-	        if("TCP-PASSIVE".equals(streamMode)) {
-	        	content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
+			content.append("v=0\r\n");
+			content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
+			content.append("s=Play\r\n");
+			content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n");
+			content.append("t=0 0\r\n");
+			if("TCP-PASSIVE".equals(streamMode)) {
+				content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
 			}else if ("TCP-ACTIVE".equals(streamMode)) {
-				content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
+				content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
 			}else if("UDP".equals(streamMode)) {
-	        	content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n");
+				content.append("m=video "+ mediaPort +" RTP/AVP 126 125 99 34 98 97 96\r\n");
 			}
-	        content.append("a=recvonly\r\n");
-	        content.append("a=rtpmap:96 PS/90000\r\n");
-	        content.append("a=rtpmap:98 H264/90000\r\n");
-	        content.append("a=rtpmap:97 MPEG4/90000\r\n");
-	        if("TCP-PASSIVE".equals(streamMode)){ // tcp琚姩妯″紡
-	        	content.append("a=setup:passive\r\n");
+			content.append("a=recvonly\r\n");
+			content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
+			content.append("a=rtpmap:126 H264/90000\r\n");
+			content.append("a=rtpmap:125 H264S/90000\r\n");
+			content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
+			content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
+			content.append("a=fmtp:99 profile-level-id=3\r\n");
+			content.append("a=rtpmap:98 H264/90000\r\n");
+			content.append("a=rtpmap:97 MPEG4/90000\r\n");
+			content.append("a=rtpmap:96 PS/90000\r\n");
+			if("TCP-PASSIVE".equals(streamMode)){ // tcp琚姩妯″紡
+				content.append("a=setup:passive\r\n");
 				content.append("a=connection:new\r\n");
-	        }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp涓诲姩妯″紡
+			}else if ("TCP-ACTIVE".equals(streamMode)) { // tcp涓诲姩妯″紡
 				content.append("a=setup:active\r\n");
 				content.append("a=connection:new\r\n");
 			}
-	        content.append("y="+ssrc+"\r\n");//ssrc
-	        
-	        Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc);
-	
-	        ClientTransaction transaction = transmitRequest(device, request);
-	        streamSession.put(ssrc, transaction);
+			content.append("y="+ssrc+"\r\n");//ssrc
+
+			Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc);
+
+			ClientTransaction transaction = transmitRequest(device, request);
+			streamSession.put(ssrc, transaction);
 			DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
 			if (deviceChannel != null) {
 				deviceChannel.setSsrc(ssrc);
 				storager.updateChannel(device.getDeviceId(), deviceChannel);
 			}
 
-			StreamInfo streamInfo = new StreamInfo();
-			streamInfo.setSsrc(ssrc);
-			streamInfo.setCahnnelId(channelId);
-			streamInfo.setDeviceID(device.getDeviceId());
-			storager.startPlay(streamInfo);
-			return streamInfo;
+			// TODO 璁㈤槄SIP response锛屽鐞嗗鏂圭殑閿欒杩斿洖
+
+
 		} catch ( SipException | ParseException | InvalidArgumentException e) {
 			e.printStackTrace();
-			return null;
-		} 
+		}
 	}
 	
 	/**
@@ -340,10 +354,18 @@
 	 * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 */ 
 	@Override
-	public StreamInfo playbackStreamCmd(Device device, String channelId, String startTime, String endTime) {
+	public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event) {
 		try {
 			MediaServerConfig mediaInfo = storager.getMediaInfo();
 			String ssrc = streamSession.createPlayBackSsrc();
+			String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
+			// 娣诲姞璁㈤槄
+			JSONObject subscribeKey = new JSONObject();
+			subscribeKey.put("app", "rtp");
+			subscribeKey.put("id", streamId);
+
+			subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, subscribeKey, event);
+
 			//
 			StringBuffer content = new StringBuffer(200);
 	        content.append("v=0\r\n");
@@ -362,16 +384,22 @@
 			}
 			String streamMode = device.getStreamMode().toUpperCase();
 			if("TCP-PASSIVE".equals(streamMode)) {
-				content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
+				content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
 			}else if ("TCP-ACTIVE".equals(streamMode)) {
-				content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
+				content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
 			}else if("UDP".equals(streamMode)) {
-				content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n");
+				content.append("m=video "+ mediaPort +" RTP/AVP 126 125 99 34 98 97 96\r\n");
 			}
-	        content.append("a=recvonly\r\n");
-	        content.append("a=rtpmap:96 PS/90000\r\n");
-	        content.append("a=rtpmap:98 H264/90000\r\n");
-	        content.append("a=rtpmap:97 MPEG4/90000\r\n");
+			content.append("a=recvonly\r\n");
+			content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
+			content.append("a=rtpmap:126 H264/90000\r\n");
+			content.append("a=rtpmap:125 H264S/90000\r\n");
+			content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
+			content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
+			content.append("a=fmtp:99 profile-level-id=3\r\n");
+			content.append("a=rtpmap:98 H264/90000\r\n");
+			content.append("a=rtpmap:97 MPEG4/90000\r\n");
+			content.append("a=rtpmap:96 PS/90000\r\n");
 			if("TCP-PASSIVE".equals(streamMode)){ // tcp琚姩妯″紡
 				content.append("a=setup:passive\r\n");
 				content.append("a=connection:new\r\n");
@@ -386,16 +414,8 @@
 	        ClientTransaction transaction = transmitRequest(device, request);
 	        streamSession.put(ssrc, transaction);
 
-			StreamInfo streamInfo = new StreamInfo();
-			streamInfo.setSsrc(ssrc);
-			streamInfo.setCahnnelId(channelId);
-			streamInfo.setDeviceID(device.getDeviceId());
-			boolean b = storager.startPlayback(streamInfo);
-			return streamInfo;
-
 		} catch ( SipException | ParseException | InvalidArgumentException e) {
 			e.printStackTrace();
-			return null;
 		}
 	}
 	
@@ -433,6 +453,7 @@
 				clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);
 			}
 			dialog.sendRequest(clientTransaction);
+			streamSession.remove(ssrc);
 		} catch (TransactionDoesNotExistException e) {
 			e.printStackTrace();
 		} catch (SipException e) {
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 aebc601..13d630c 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
@@ -21,14 +21,12 @@
 	 * 澶勭悊  ACK璇锋眰
 	 * 
 	 * @param evt
-	 * @param layer
-	 * @param transaction
-	 * @param config    
-	 */  
+	 */
 	@Override
 	public void process(RequestEvent evt) {
 		Request request = evt.getRequest();
 		Dialog dialog = evt.getDialog();
+		if (dialog == null) return;
 		try {
 			Request ackRequest = null;
 			CSeq csReq = (CSeq) request.getHeader(CSeq.NAME);
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 0730731..0ba6bd8 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
@@ -1,8 +1,13 @@
 package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
 
+import javax.sip.InvalidArgumentException;
 import javax.sip.RequestEvent;
+import javax.sip.SipException;
+import javax.sip.message.Response;
 
 import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
+
+import java.text.ParseException;
 
 /**    
  * @Description: BYE璇锋眰澶勭悊鍣�
@@ -11,18 +16,35 @@
  */
 public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
 
-	/**   
+	/**
 	 * 澶勭悊BYE璇锋眰
-	 * 
 	 * @param evt
-	 * @param layer
-	 * @param transaction
-	 * @param config    
-	 */  
+	 */
 	@Override
 	public void process(RequestEvent evt) {
+		try {
+			responseAck(evt);
+		} catch (SipException e) {
+			e.printStackTrace();
+		} catch (InvalidArgumentException e) {
+			e.printStackTrace();
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
 		// TODO 浼樺厛绾�99 Bye Request娑堟伅瀹炵幇锛屾娑堟伅涓�鑸负绾ц仈娑堟伅锛屼笂绾х粰涓嬬骇鍙戦�佽棰戝仠姝㈡寚浠�
 		
 	}
 
+	/***
+	 * 鍥炲200 OK
+	 * @param evt
+	 * @throws SipException
+	 * @throws InvalidArgumentException
+	 * @throws ParseException
+	 */
+	private void responseAck(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
+		Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
+		getServerTransaction(evt).sendResponse(response);
+	}
+
 }
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 4c95cf1..c987f5e 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
@@ -184,10 +184,11 @@
 					DeviceChannel deviceChannel = new DeviceChannel();
 					deviceChannel.setName(channelName);
 					deviceChannel.setChannelId(channelDeviceId);
-					if (status.equals("ON") || status.equals("On")) {
+					// ONLINE OFFLINE  HIKVISION DS-7716N-E4 NVR鐨勫吋瀹规�у鐞�
+					if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) {
 						deviceChannel.setStatus(1);
 					}
-					if (status.equals("OFF") || status.equals("Off")) {
+					if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
 						deviceChannel.setStatus(0);
 					}
 
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 b9c05e4..99da624 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
@@ -49,6 +49,9 @@
 	@Autowired
 	private ZLMRESTfulUtils zlmresTfulUtils;
 
+	@Autowired
+	private ZLMHttpHookSubscribe subscribe;
+
 	@Value("${media.ip}")
 	private String mediaIp;
 
@@ -128,30 +131,38 @@
 		}
 		String app = json.getString("app");
 		String streamId = json.getString("id");
-		if ("rtp".equals(app)) {
-			String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
-			StreamInfo streamInfoForPlay = storager.queryPlayBySSRC(ssrc);
-			if ("rtp".equals(app) && streamInfoForPlay != null ) {
-				MediaServerConfig mediaInfo = storager.getMediaInfo();
-				streamInfoForPlay.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-				streamInfoForPlay.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-				streamInfoForPlay.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
-				streamInfoForPlay.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-				streamInfoForPlay.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
-				storager.startPlay(streamInfoForPlay);
-			}
 
-			StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc);
-			if ("rtp".equals(app) && streamInfoForPlayBack != null ) {
-				MediaServerConfig mediaInfo = storager.getMediaInfo();
-				streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-				streamInfoForPlayBack.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-				streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
-				streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-				streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
-				storager.startPlayback(streamInfoForPlayBack);
-			}
-		}
+		ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
+		if (subscribe != null) subscribe.response(json);
+
+//		if ("rtp".equals(app)) {
+//			String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
+//			StreamInfo streamInfoForPlay = storager.queryPlayBySSRC(ssrc);
+//			if ("rtp".equals(app) && streamInfoForPlay != null ) {
+//				MediaServerConfig mediaInfo = storager.getMediaInfo();
+//				streamInfoForPlay.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+//				streamInfoForPlay.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+//				streamInfoForPlay.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+//				streamInfoForPlay.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+//				streamInfoForPlay.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
+//				streamInfoForPlay.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+//				streamInfoForPlay.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
+//				storager.startPlay(streamInfoForPlay);
+//			}
+//
+//			StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc);
+//			if ("rtp".equals(app) && streamInfoForPlayBack != null ) {
+//				MediaServerConfig mediaInfo = storager.getMediaInfo();
+//				streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+//				streamInfoForPlayBack.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+//				streamInfoForPlayBack.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+//				streamInfoForPlayBack.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+//				streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
+//				streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+//				streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
+//				storager.startPlayback(streamInfoForPlayBack);
+//			}
+//		}
 
 		// TODO Auto-generated method stub
 		
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
new file mode 100644
index 0000000..0c00b82
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
@@ -0,0 +1,90 @@
+package com.genersoft.iot.vmp.media.zlm;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
+import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+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.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ConcurrentReferenceHashMap;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigInteger;
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @Description:閽堝 ZLMediaServer鐨刪ook浜嬩欢璁㈤槄
+ * @author: pan
+ * @date:   2020骞�12鏈�2鏃� 21:17:32
+ */
+@Component
+public class ZLMHttpHookSubscribe {
+
+    private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookSubscribe.class);
+
+    public enum HookType{
+        on_flow_report,
+        on_http_access,
+        on_play,
+        on_publish,
+        on_record_mp4,
+        on_rtsp_auth,
+        on_rtsp_realm,
+        on_shell_login,
+        on_stream_changed,
+        on_stream_none_reader,
+        on_stream_not_found,
+        on_server_started
+    }
+
+    public interface Event{
+        void response(JSONObject response);
+    }
+
+    private Map<HookType, Map<JSONObject, ZLMHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
+
+    public void addSubscribe(HookType type, JSONObject hookResponse, ZLMHttpHookSubscribe.Event event) {
+        Map<JSONObject, Event> eventMap = allSubscribes.get(type);
+        if (eventMap == null) {
+            eventMap = new HashMap<JSONObject, Event>();
+            allSubscribes.put(type,eventMap);
+        }
+        eventMap.put(hookResponse, event);
+    }
+
+    public ZLMHttpHookSubscribe.Event getSubscribe(HookType type, JSONObject hookResponse) {
+        ZLMHttpHookSubscribe.Event event= null;
+        Map<JSONObject, Event> eventMap = allSubscribes.get(type);
+        if (eventMap == null) {
+            return null;
+        }
+        for (JSONObject key : eventMap.keySet()) {
+            Boolean result = null;
+            for (String s : key.keySet()) {
+                String string = hookResponse.getString(s);
+                String string1 = key.getString(s);
+                if (result == null) {
+                    result = key.getString(s).equals(hookResponse.getString(s));
+                }else {
+                    result = result && key.getString(s).equals(hookResponse.getString(s));
+                }
+
+            }
+            if (result) {
+                event = eventMap.get(key);
+            }
+        }
+        return event;
+    }
+}
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 66f8e61..3f88b2a 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
@@ -36,6 +36,9 @@
     @Value("${media.wanIp}")
     private String mediaWanIp;
 
+    @Value("${media.hookIp}")
+    private String mediaHookIp;
+
     @Value("${media.port}")
     private int mediaPort;
 
@@ -51,6 +54,9 @@
     @Value("${server.port}")
     private String serverPort;
 
+    @Value("${media.autoConfig}")
+    private boolean autoConfig;
+
     @Autowired
     private ZLMRESTfulUtils zlmresTfulUtils;
 
@@ -61,8 +67,7 @@
         MediaServerConfig mediaServerConfig = getMediaServerConfig();
         if (mediaServerConfig != null) {
             logger.info("zlm鎺ュ叆鎴愬姛...");
-            logger.info("璁剧疆zlm...");
-            saveZLMConfig();
+            if (autoConfig) saveZLMConfig();
             mediaServerConfig = getMediaServerConfig();
             storager.updateMediaInfo(mediaServerConfig);
         }
@@ -91,12 +96,12 @@
     }
 
     private void saveZLMConfig() {
-        String hookIP = sipIP;
-        if (mediaIp.equals(sipIP)) {
-            hookIP = "127.0.0.1";
+        logger.info("璁剧疆zlm...");
+        if (StringUtils.isEmpty(mediaHookIp)) {
+            mediaHookIp = sipIP;
         }
 
-        String hookPrex = String.format("http://%s:%s/index/hook", hookIP, serverPort);
+        String hookPrex = String.format("http://%s:%s/index/hook", mediaHookIp, serverPort);
         Map<String, Object> param = new HashMap<>();
         param.put("api.secret",mediaSecret); // -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");
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
index ad77995..99c7f06 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
@@ -555,6 +555,10 @@
 		List<Object> playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
 				deviceId,
 				code));
+		if (playLeys == null || playLeys.size() == 0) {
+			playLeys = redis.scan(String.format("%S_*_*_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
+				deviceId));
+		}
 		if (playLeys == null || playLeys.size() == 0) return null;
 		return (StreamInfo)redis.get(playLeys.get(0).toString());
 	}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
index 300ffc3..e741b5a 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
@@ -4,7 +4,10 @@
 import com.alibaba.fastjson.JSONArray;
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.MediaServerConfig;
+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.vmanager.service.IPlayService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -22,6 +25,10 @@
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+import org.springframework.web.context.request.async.DeferredResult;
+
+import java.text.DecimalFormat;
+import java.util.UUID;
 
 @CrossOrigin
 @RestController
@@ -39,94 +46,57 @@
 	@Autowired
 	private ZLMRESTfulUtils zlmresTfulUtils;
 
-	@Value("${media.closeWaitRTPInfo}")
-	private boolean closeWaitRTPInfo;
+	@Autowired
+	private DeferredResultHolder resultHolder;
+
+	@Autowired
+	private IPlayService playService;
 
 	@GetMapping("/play/{deviceId}/{channelId}")
-	public ResponseEntity<String> play(@PathVariable String deviceId, @PathVariable String channelId,
-	Integer getEncoding) {
+	public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId,
+													   @PathVariable String channelId) {
 
-		if (getEncoding == null) getEncoding = 0;
-		getEncoding = closeWaitRTPInfo ?  0 : getEncoding;
+
 		Device device = storager.queryVideoDevice(deviceId);
 		StreamInfo streamInfo = storager.queryPlayByDevice(deviceId, channelId);
 
+		UUID uuid = UUID.randomUUID();
+		DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();
+		// 瓒呮椂澶勭悊
+		result.onTimeout(()->{
+			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);
+		});
+		// 褰曞儚鏌ヨ浠hannelId浣滀负deviceId鏌ヨ
+		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
+
 		if (streamInfo == null) {
-			streamInfo = cmder.playStreamCmd(device, channelId);
+			// 鍙戦�佺偣鎾秷鎭�
+			cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
+				logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
+				playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
+			});
 		} else {
 			String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
 			JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
 			if (rtpInfo.getBoolean("exist")) {
-				return new ResponseEntity<String>(JSON.toJSONString(streamInfo), HttpStatus.OK);
+				RequestMessage msg = new RequestMessage();
+				msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
+				msg.setData(JSON.toJSONString(streamInfo));
+				resultHolder.invokeResult(msg);
 			} else {
 				storager.stopPlay(streamInfo);
-				streamInfo = cmder.playStreamCmd(device, channelId);
+				// TODO playStreamCmd 瓒呮椂澶勭悊
+				cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
+					logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
+					playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
+				});
 			}
 		}
-		String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
-		// 绛夊緟鎺ㄦ祦, TODO 榛樿瓒呮椂30s
-		boolean lockFlag = true;
-		boolean rtpPushed = false;
-		long startTime = System.currentTimeMillis();
-		JSONObject rtpInfo = null;
-
-		if (getEncoding == 1) {
-			while (lockFlag) {
-				try {
-					if (System.currentTimeMillis() - startTime > 60 * 1000) {
-						storager.stopPlay(streamInfo);
-						logger.info("鎾斁绛夊緟瓒呮椂");
-						return new ResponseEntity<String>("timeout", HttpStatus.OK);
-					} else {
-						streamInfo = storager.queryPlayByDevice(deviceId, channelId);
-						if (!rtpPushed) {
-							logger.info("鏌ヨRTP鎺ㄦ祦淇℃伅...");
-							rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
-						}
-						if (rtpInfo != null && rtpInfo.getBoolean("exist") && streamInfo != null
-								&& streamInfo.getFlv() != null) {
-							logger.info("鏌ヨ娴佺紪鐮佷俊鎭細" + streamInfo.getFlv());
-							rtpPushed = true;
-							Thread.sleep(2000);
-							JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo("rtp", "rtmp", streamId);
-							if (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online")) {
-								lockFlag = false;
-								logger.info("娴佺紪鐮佷俊鎭凡鑾峰彇");
-								JSONArray tracks = mediaInfo.getJSONArray("tracks");
-								streamInfo.setTracks(tracks);
-								storager.startPlay(streamInfo);
-							} else {
-								logger.info("娴佺紪鐮佷俊鎭湭鑾峰彇锛�2绉掑悗閲嶈瘯...");
-							}
-						} else {
-							Thread.sleep(2000);
-							continue;
-						}
-					}
-				} catch (InterruptedException e) {
-					e.printStackTrace();
-				}
-			}
-		} else {
-			String flv = storager.getMediaInfo().getWanIp() + ":" + storager.getMediaInfo().getHttpPort() + "/rtp/"
-					+ streamId + ".flv";
-			streamInfo.setFlv("http://" + flv);
-			streamInfo.setWs_flv("ws://" + flv);
-			storager.startPlay(streamInfo);
-		}
-
-		if (logger.isDebugEnabled()) {
-			logger.debug(String.format("璁惧棰勮 API璋冪敤锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId));
-			logger.debug("璁惧棰勮 API璋冪敤锛宻src锛�" + streamInfo.getSsrc() + ",ZLMedia streamId:"
-					+ Integer.toHexString(Integer.parseInt(streamInfo.getSsrc())));
-		}
-
-		if (streamInfo != null) {
-			return new ResponseEntity<String>(JSON.toJSONString(streamInfo), HttpStatus.OK);
-		} else {
-			logger.warn("璁惧棰勮API璋冪敤澶辫触锛�");
-			return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
-		}
+		return result;
 	}
 
 	@PostMapping("/play/{ssrc}/stop")
@@ -172,17 +142,28 @@
 			MediaServerConfig mediaInfo = storager.getMediaInfo();
 			String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(),
 					streamId );
-			JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(streamInfo.getRtsp(), dstUrl, "1000000");
+			String srcUrl = String.format("rtsp://%s:%s/rtp/%s", "127.0.0.1", mediaInfo.getRtspPort(), streamId);
+			JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(srcUrl, dstUrl, "1000000");
 			System.out.println(jsonObject);
 			JSONObject result = new JSONObject();
 			if (jsonObject != null && jsonObject.getInteger("code") == 0) {
 				   result.put("code", 0);
 				JSONObject data = jsonObject.getJSONObject("data");
 				if (data != null) {
-				   result.put("key", data.getString("key"));
-					result.put("rtmp", dstUrl);
-					result.put("flv", String.format("http://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-					result.put("ws_flv", String.format("ws://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+				   	result.put("key", data.getString("key"));
+					StreamInfo streamInfoResult = new StreamInfo();
+					streamInfoResult.setRtmp(dstUrl);
+					streamInfoResult.setRtsp(String.format("rtsp://%s:%s/convert/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
+					streamInfoResult.setStreamId(streamId);
+					streamInfoResult.setFlv(String.format("http://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+					streamInfoResult.setWs_flv(String.format("ws://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+					streamInfoResult.setHls(String.format("http://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+					streamInfoResult.setWs_hls(String.format("ws://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+					streamInfoResult.setFmp4(String.format("http://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+					streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+					streamInfoResult.setTs(String.format("http://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+					streamInfoResult.setWs_ts(String.format("ws://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
+					result.put("data", streamInfoResult);
 				}
 			}else {
 				result.put("code", 1);
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
index 16713fe..2e32b1b 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
@@ -3,7 +3,10 @@
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.genersoft.iot.vmp.common.StreamInfo;
+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.vmanager.service.IPlayService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -22,6 +25,9 @@
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+import org.springframework.web.context.request.async.DeferredResult;
+
+import java.util.UUID;
 
 @CrossOrigin
 @RestController
@@ -39,105 +45,42 @@
 	@Autowired
 	private ZLMRESTfulUtils zlmresTfulUtils;
 
-	@Value("${media.closeWaitRTPInfo}")
-	private boolean closeWaitRTPInfo;
+	@Autowired
+	private IPlayService playService;
+
+	@Autowired
+	private DeferredResultHolder resultHolder;
 
 	@GetMapping("/playback/{deviceId}/{channelId}")
-	public ResponseEntity<String> play(@PathVariable String deviceId, @PathVariable String channelId, String startTime,
-			String endTime) {
+	public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId, @PathVariable String channelId, String startTime,
+													   String endTime) {
 
 		if (logger.isDebugEnabled()) {
 			logger.debug(String.format("璁惧鍥炴斁 API璋冪敤锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId));
 		}
-
-		if (StringUtils.isEmpty(deviceId) || StringUtils.isEmpty(channelId)) {
-			String log = String.format("璁惧鍥炴斁 API璋冪敤澶辫触锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId);
-			logger.warn(log);
-			return new ResponseEntity<String>(log, HttpStatus.BAD_REQUEST);
-		}
-
+		UUID uuid = UUID.randomUUID();
+		DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();
+		// 瓒呮椂澶勭悊
+		result.onTimeout(()->{
+			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);
+		});
 		Device device = storager.queryVideoDevice(deviceId);
 		StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId);
-
 		if (streamInfo != null) {
+			// 鍋滄涔嬪墠鐨勫洖鏀�
 			cmder.streamByeCmd(streamInfo.getSsrc());
 		}
+		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
+		cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> {
+			logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
+			playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString());
+		});
 
-		// }else {
-		// String streamId = String.format("%08x",
-		// Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
-		// JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
-		// if (rtpInfo.getBoolean("exist")) {
-		// return new
-		// ResponseEntity<String>(JSON.toJSONString(streamInfo),HttpStatus.OK);
-		// }else {
-		// storager.stopPlayback(streamInfo);
-		// streamInfo = cmder.playbackStreamCmd(device, channelId, startTime, endTime);
-		// }
-		// }
-		streamInfo = cmder.playbackStreamCmd(device, channelId, startTime, endTime);
-
-		String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
-
-		if (logger.isDebugEnabled()) {
-			logger.debug("璁惧鍥炴斁 API璋冪敤锛宻src锛�" + streamInfo.getSsrc() + ",ZLMedia streamId:" + streamId);
-		}
-		// 绛夊緟鎺ㄦ祦, TODO 榛樿瓒呮椂15s
-		boolean lockFlag = true;
-		boolean rtpPushed = false;
-		long lockStartTime = System.currentTimeMillis();
-		JSONObject rtpInfo = null;
-
-		if (closeWaitRTPInfo) {
-			String flv = storager.getMediaInfo().getWanIp() + ":" + storager.getMediaInfo().getHttpPort() + "/rtp/"
-					+ streamId + ".flv";
-			streamInfo.setFlv("http://" + flv);
-			streamInfo.setWs_flv("ws://" + flv);
-			storager.startPlayback(streamInfo);
-		} else {
-			while (lockFlag) {
-				try {
-					if (System.currentTimeMillis() - lockStartTime > 75 * 1000) {
-						storager.stopPlayback(streamInfo);
-						logger.info("鎾斁绛夊緟瓒呮椂");
-						return new ResponseEntity<String>("timeout", HttpStatus.OK);
-					} else {
-						streamInfo = storager.queryPlaybackByDevice(deviceId, channelId);
-						if (!rtpPushed) {
-							logger.info("鏌ヨRTP鎺ㄦ祦淇℃伅...");
-							rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
-						}
-						if (rtpInfo != null && rtpInfo.getBoolean("exist") && streamInfo != null
-								&& streamInfo.getFlv() != null) {
-							logger.info("鏌ヨ娴佺紪鐮佷俊鎭細" + streamInfo.getFlv());
-							rtpPushed = true;
-							Thread.sleep(2000);
-							JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo("rtp", "rtmp", streamId);
-							if (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online")) {
-								lockFlag = false;
-								logger.info("娴佺紪鐮佷俊鎭凡鑾峰彇");
-								JSONArray tracks = mediaInfo.getJSONArray("tracks");
-								streamInfo.setTracks(tracks);
-								storager.startPlayback(streamInfo);
-							} else {
-								logger.info("娴佺紪鐮佷俊鎭湭鑾峰彇锛�2绉掑悗閲嶈瘯...");
-							}
-						} else {
-							Thread.sleep(2000);
-							continue;
-						}
-					}
-				} catch (InterruptedException e) {
-					e.printStackTrace();
-				}
-			}
-		}
-		if (streamInfo != null) {
-			return new ResponseEntity<String>(JSON.toJSONString(streamInfo), HttpStatus.OK);
-		} else {
-			logger.warn("璁惧鍥炴斁API璋冪敤澶辫触锛�");
-			return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
-		}
+		return result;
 	}
 
 	@RequestMapping("/playback/{ssrc}/stop")
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java b/src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java
new file mode 100644
index 0000000..a80ab5d
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java
@@ -0,0 +1,13 @@
+package com.genersoft.iot.vmp.vmanager.service;
+
+import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.common.StreamInfo;
+
+/**
+ * 鐐规挱澶勭悊
+ */
+public interface IPlayService {
+
+    void onPublishHandlerForPlayBack(JSONObject resonse, String deviceId, String channelId, String uuid);
+    void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, String uuid);
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
new file mode 100644
index 0000000..e9528d1
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
@@ -0,0 +1,90 @@
+package com.genersoft.iot.vmp.vmanager.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
+import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
+import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+import com.genersoft.iot.vmp.vmanager.play.PlayController;
+import com.genersoft.iot.vmp.vmanager.service.IPlayService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.text.DecimalFormat;
+
+@Service
+public class PlayServiceImpl implements IPlayService {
+
+    private final static Logger logger = LoggerFactory.getLogger(PlayServiceImpl.class);
+
+    @Autowired
+    private IVideoManagerStorager storager;
+
+    @Autowired
+    private DeferredResultHolder resultHolder;
+
+    @Override
+    public void onPublishHandlerForPlay(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);
+        if (streamInfo != null) {
+            storager.startPlay(streamInfo);
+            msg.setData(JSON.toJSONString(streamInfo));
+            resultHolder.invokeResult(msg);
+        } else {
+            logger.warn("璁惧棰勮API璋冪敤澶辫触锛�");
+            msg.setData("璁惧棰勮API璋冪敤澶辫触锛�");
+            resultHolder.invokeResult(msg);
+        }
+    }
+
+    @Override
+    public void onPublishHandlerForPlayBack(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);
+        if (streamInfo != null) {
+            storager.startPlayback(streamInfo);
+            msg.setData(JSON.toJSONString(streamInfo));
+            resultHolder.invokeResult(msg);
+        } else {
+            logger.warn("璁惧棰勮API璋冪敤澶辫触锛�");
+            msg.setData("璁惧棰勮API璋冪敤澶辫触锛�");
+            resultHolder.invokeResult(msg);
+        }
+    }
+
+    public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) {
+        String streamId = resonse.getString("id");
+        String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
+        StreamInfo streamInfo = new StreamInfo();
+        streamInfo.setSsrc(ssrc);
+        streamInfo.setStreamId(streamId);
+        streamInfo.setDeviceID(deviceId);
+        streamInfo.setCahnnelId(channelId);
+        MediaServerConfig mediaServerConfig = storager.getMediaInfo();
+
+        streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
+        streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
+
+        streamInfo.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
+        streamInfo.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
+
+        streamInfo.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
+        streamInfo.setWs_hls(String.format("ws://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
+
+        streamInfo.setTs(String.format("http://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
+        streamInfo.setWs_ts(String.format("ws://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
+
+        streamInfo.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtmpPort(), streamId));
+        streamInfo.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtspPort(), streamId));
+
+        return streamInfo;
+    }
+
+}
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 40b1b5b..6180fbb 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
@@ -34,8 +34,7 @@
     @Autowired
     private IVideoManagerStorager storager;
 
-    @Value("${media.closeWaitRTPInfo}")
-    private boolean closeWaitRTPInfo;
+    private boolean closeWaitRTPInfo = false;
 
 
     @Autowired
@@ -94,7 +93,7 @@
         StreamInfo streamInfo = storager.queryPlayByDevice(device.getDeviceId(), code);
         if (streamInfo == null) {
             logger.debug("streamInfo 绛変簬null, 閲嶆柊鐐规挱");
-            streamInfo = cmder.playStreamCmd(device, code);
+//            streamInfo = cmder.playStreamCmd(device, code);
         }else {
             logger.debug("streamInfo 涓嶇瓑浜巒ull, 鍚戞祦濯掍綋鏌ヨ鏄惁姝e湪鎺ㄦ祦");
             String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
@@ -136,7 +135,7 @@
             } else {
                 logger.debug("鍚戞祦濯掍綋鏌ヨ娌℃湁鎺ㄦ祦, 閲嶆柊鐐规挱");
                 storager.stopPlay(streamInfo);
-                streamInfo = cmder.playStreamCmd(device, code);
+//                streamInfo = cmder.playStreamCmd(device, code);
             }
         }
 
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..638d5ae
--- /dev/null
+++ b/src/main/resources/application-dev.yml
@@ -0,0 +1,94 @@
+spring:
+    # [涓嶉渶瑕佹敼]
+    application:
+        name: iot-vmp-vmanager
+        # [涓嶉渶瑕佹敼] 褰卞瓙鏁版嵁瀛樺偍鏂瑰紡锛屾敮鎸乺edis銆乯dbc,鏆備笉鏀寔mysql,
+        database: redis
+        # [涓嶉渶瑕佹敼] 閫氫俊鏂瑰紡锛屾敮鎸乲afka銆乭ttp
+        communicate: http
+    # REDIS鏁版嵁搴撻厤缃�
+    redis:
+        # [蹇呴』淇敼] Redis鏈嶅姟鍣↖P, REDIS瀹夎鍦ㄦ湰鏈虹殑,浣跨敤127.0.0.1
+        host: 127.0.0.1
+        # [蹇呴』淇敼] 绔彛鍙�
+        port: 6379
+        # [鍙�塢 鏁版嵁搴� DB
+        database: 6
+        # [鍙�塢 璁块棶瀵嗙爜,鑻ヤ綘鐨剅edis鏈嶅姟鍣ㄦ病鏈夎缃瘑鐮侊紝灏变笉闇�瑕佺敤瀵嗙爜鍘昏繛鎺�
+        password:
+        # [鍙�塢 瓒呮椂鏃堕棿
+        timeout: 10000
+    # [涓嶅彲鐢╙ jdbc鏁版嵁搴撻厤缃�, 鏆備笉鏀寔
+    datasource:
+        name: eiot
+        url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
+        username:
+        password:
+        type: com.alibaba.druid.pool.DruidDataSource
+        driver-class-name: com.mysql.jdbc.Driver
+
+# [鍙�塢 WVP鐩戝惉鐨凥TTP绔彛, 缃戦〉鍜屾帴鍙h皟鐢ㄩ兘鏄繖涓鍙�
+server:
+    port: 18080
+
+# 浣滀负28181鏈嶅姟鍣ㄧ殑閰嶇疆
+sip:
+    # [蹇呴』淇敼] 鏈満鐨処P, 蹇呴』鏄綉鍗′笂鐨処P
+    ip: 192.168.0.100
+    # [鍙�塢 28181鏈嶅姟鐩戝惉鐨勭鍙�
+    port: 5060
+    # 鏍规嵁鍥芥爣6.1.2涓瀹氾紝domain瀹滈噰鐢↖D缁熶竴缂栫爜鐨勫墠鍗佷綅缂栫爜銆傚浗鏍囬檮褰旸涓畾涔夊墠8浣嶄负涓績缂栫爜锛堢敱鐪佺骇銆佸競绾с�佸尯绾с�佸熀灞傜紪鍙风粍鎴愶紝鍙傜収GB/T 2260-2007锛�
+    # 鍚庝袱浣嶄负琛屼笟缂栫爜锛屽畾涔夊弬鐓ч檮褰旸.3
+    # 3701020049鏍囪瘑灞变笢娴庡崡鍘嗕笅鍖� 淇℃伅琛屼笟鎺ュ叆
+    # [鍙�塢
+    domain: 4401020049
+    # [鍙�塢
+    id: 44010200492000000001
+    # [鍙�塢 榛樿璁惧璁よ瘉瀵嗙爜锛屽悗缁墿灞曚娇鐢ㄨ澶囧崟鐙瘑鐮�
+    password: admin123
+
+# 鐧婚檰鐨勭敤鎴峰悕瀵嗙爜
+auth:
+    # [鍙�塢 鐢ㄦ埛鍚�
+    username: admin
+    # [鍙�塢 瀵嗙爜, 榛樿涓篴dmin
+    password: 21232f297a57a5a743894a0e4a801fc3
+
+#zlm鏈嶅姟鍣ㄩ厤缃�
+media:
+    # [蹇呴』淇敼] zlm鏈嶅姟鍣ㄧ殑鍐呯綉IP
+    ip: 192.168.0.100
+    # [鍙�塢 zlm鏈嶅姟鍣ㄧ殑鍏綉IP, 鍐呯綉閮ㄧ讲缃┖鍗冲彲
+    wanIp:
+    # [鍙�塢 zlm鏈嶅姟鍣ㄧ殑hook鎵�浣跨敤鐨処P, 榛樿浣跨敤sip.ip
+    hookIp:
+    # [蹇呴』淇敼] zlm鏈嶅姟鍣ㄧ殑http.port
+    port: 80
+    # [鍙�塢 鏄惁鑷姩閰嶇疆ZLM, 濡傛灉甯屾湜鎵嬪姩閰嶇疆ZLM, 鍙互璁句负false, 涓嶅缓璁柊鎺ヨЕ鐨勭敤鎴蜂慨鏀�
+    autoConfig: true
+    # [鍙�塢 zlm鏈嶅姟鍣ㄧ殑hook.admin_params=secret
+    secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
+    # [鍙�塢 zlm鏈嶅姟鍣ㄧ殑general.streamNoneReaderDelayMS
+    streamNoneReaderDelayMS:  18000  # 鏃犱汉瑙傜湅澶氫箙鑷姩鍏抽棴娴�
+    # [鍙�塢 鍏抽棴绛夊緟鏀跺埌娴佺紪鐮佷俊鎭悗鍦ㄨ繑鍥�,
+    # 璁句负false鍙互鑾峰緱鏇村ソ鐨勫吋瀹规��,淇濊瘉杩斿洖鍚庢祦灏卞彲浠ユ挱鏀�,
+    # 璁句负true鍙互蹇�熸墦寮�鎾斁绐楀彛,鍙互鑾峰緱鏇村ソ鐨勪綋楠�
+    closeWaitRTPInfo: false
+    # 鍚敤udp澶氱鍙fā寮�
+    rtp:
+        # [鍙�塢 鏄惁鍚敤udp澶氱鍙fā寮�, 寮�鍚悗浼氬湪udpPortRange鑼冨洿鍐呴�夋嫨绔彛鐢ㄤ簬濯掍綋娴佷紶杈�
+        enable: true
+        # [鍙�塢 鍦ㄦ鑼冨洿鍐呴�夋嫨绔彛鐢ㄤ簬濯掍綋娴佷紶杈�, 涓嶅彧鏄痷dp, 浣跨敤TCP琚姩浼犺緭妯″紡鏃�,涔熸槸浠庤繖涓寖鍥村唴閫夋嫨绔彛
+        udpPortRange: 30000,30500 # 绔彛鑼冨洿
+
+# [鍙�塢 鏃ュ織閰嶇疆, 涓�鑸笉闇�瑕佹敼
+logging:
+    file:
+        name: logs/wvp.log
+        max-history: 30
+        max-size: 10MB
+        total-size-cap: 300MB
+    level:
+        com:
+            genersoft:
+                iot: debug
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index fd7509e..caf4dfc 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -1,64 +1,3 @@
 spring:
-    application:
-        name: iot-vmp-vmanager
-        # 褰卞瓙鏁版嵁瀛樺偍鏂瑰紡锛屾敮鎸乺edis銆乯dbc,鏆備笉鏀寔mysql
-        database: redis
-        # 閫氫俊鏂瑰紡锛屾敮鎸乲afka銆乭ttp
-        communicate: http
-    redis:
-        # Redis鏈嶅姟鍣↖P
-        host: 192.168.1.141
-        #绔彛鍙�
-        port: 6379
-        database: 6
-        #璁块棶瀵嗙爜,鑻ヤ綘鐨剅edis鏈嶅姟鍣ㄦ病鏈夎缃瘑鐮侊紝灏变笉闇�瑕佺敤瀵嗙爜鍘昏繛鎺�
-        password: 4767cb971b40a1300fa09b7f87b09d1c
-        #瓒呮椂鏃堕棿
-        timeout: 10000
-    datasource: 
-        name: eiot
-        url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
-        username:
-        password:
-        type: com.alibaba.druid.pool.DruidDataSource
-        driver-class-name: com.mysql.jdbc.Driver
-server:
-    port: 18080
-sip:
-    ip: 192.168.1.20
-    port: 5060
-    # 鏍规嵁鍥芥爣6.1.2涓瀹氾紝domain瀹滈噰鐢↖D缁熶竴缂栫爜鐨勫墠鍗佷綅缂栫爜銆傚浗鏍囬檮褰旸涓畾涔夊墠8浣嶄负涓績缂栫爜锛堢敱鐪佺骇銆佸競绾с�佸尯绾с�佸熀灞傜紪鍙风粍鎴愶紝鍙傜収GB/T 2260-2007锛�
-    # 鍚庝袱浣嶄负琛屼笟缂栫爜锛屽畾涔夊弬鐓ч檮褰旸.3
-    # 3701020049鏍囪瘑灞变笢娴庡崡鍘嗕笅鍖� 淇℃伅琛屼笟鎺ュ叆
-    domain: 3402000000
-    id: 34020000002000000001
-    # 榛樿璁惧璁よ瘉瀵嗙爜锛屽悗缁墿灞曚娇鐢ㄨ澶囧崟鐙瘑鐮�
-    password: 12345678
-
-auth: #32浣嶅皬鍐檓d5鍔犲瘑锛堥粯璁ゅ瘑鐮佷负admin锛�
-    username: admin
-    password: 21232f297a57a5a743894a0e4a801fc3
-
-media: #zlm鏈嶅姟鍣ㄧ殑ip涓巋ttp绔彛, 閲嶇偣: 杩欐槸http绔彛
-    ip: 127.0.0.1
-    wanIp: 192.168.1.20
-    port: 6080
-    secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
-    streamNoneReaderDelayMS:  600000  # 鏃犱汉瑙傜湅澶氫箙鑷姩鍏抽棴娴�
-    # 鍏抽棴绛夊緟鏀跺埌娴佺紪鐮佷俊鎭悗鍦ㄨ繑鍥�,
-    # 璁句负false鍙互鑾峰緱鏇村ソ鐨勫吋瀹规��,淇濊瘉杩斿洖鍚庢祦灏卞彲浠ユ挱鏀�,
-    # 璁句负true鍙互蹇�熸墦寮�鎾斁绐楀彛,鍙互鑾峰緱鏇村ソ鐨勪綋楠�
-    closeWaitRTPInfo: true
-    rtp: # 鍚敤udp澶氱鍙fā寮�
-        enable: true
-        udpPortRange: 30000,30500 # 绔彛鑼冨洿
-logging:
-    file:
-        name: logs/wvp.log
-        max-history: 30
-        max-size: 10MB
-        total-size-cap: 300MB
-    level:
-        com:
-            genersoft:
-                iot: debug
\ No newline at end of file
+  profiles:
+    active: dev
\ No newline at end of file
diff --git a/web_src/build/webpack.dev.conf.js b/web_src/build/webpack.dev.conf.js
index c12be3e..e33cb01 100755
--- a/web_src/build/webpack.dev.conf.js
+++ b/web_src/build/webpack.dev.conf.js
@@ -64,9 +64,8 @@
         to: config.dev.assetsSubDirectory,
         ignore: ['.*']
       },
-      { from: 'node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml'},
-      { from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf'},
-      { from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js', to: 'js/'}
+      { from: 'node_modules/@easydarwin/easywasmplayer/libDecoder.wasm'},
+      { from: 'node_modules/@easydarwin/easywasmplayer/EasyWasmPlayer.js', to: 'js/'}
     ])
   ]
 })
diff --git a/web_src/build/webpack.prod.conf.js b/web_src/build/webpack.prod.conf.js
index 2bfb52c..13d373d 100644
--- a/web_src/build/webpack.prod.conf.js
+++ b/web_src/build/webpack.prod.conf.js
@@ -115,9 +115,8 @@
         to: config.build.assetsSubDirectory,
         ignore: ['.*']
       },
-      { from: 'node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml'},
-      { from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf'},
-      { from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js', to: 'js/'}
+      { from: 'node_modules/@easydarwin/easywasmplayer/libDecoder.wasm'},
+      { from: 'node_modules/@easydarwin/easywasmplayer/EasyWasmPlayer.js', to: 'js/'}
     ])
   ]
 })
diff --git a/web_src/index.html b/web_src/index.html
index 9c4e39b..1224125 100644
--- a/web_src/index.html
+++ b/web_src/index.html
@@ -6,7 +6,7 @@
     <title>鍥芥爣28181</title>
   </head>
   <body>
-    <script type="text/javascript" src="./js/liveplayer-lib.min.js"></script>
+    <script type="text/javascript" src="./js/EasyWasmPlayer.js"></script>
     <div id="app"></div>
     <!-- built files will be auto injected -->
   </body>
diff --git a/web_src/package-lock.json b/web_src/package-lock.json
index e00c5ce..334f488 100644
--- a/web_src/package-lock.json
+++ b/web_src/package-lock.json
@@ -4,10 +4,10 @@
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
-    "@liveqing/liveplayer": {
-      "version": "1.9.9",
-      "resolved": "https://registry.npm.taobao.org/@liveqing/liveplayer/download/@liveqing/liveplayer-1.9.9.tgz",
-      "integrity": "sha1-K7wiab+BiY5qe1/nTpKVyeGdIGo="
+    "@easydarwin/easywasmplayer": {
+      "version": "4.0.7",
+      "resolved": "https://registry.npm.taobao.org/@easydarwin/easywasmplayer/download/@easydarwin/easywasmplayer-4.0.7.tgz",
+      "integrity": "sha1-FNtIUXbdwIWdalvIMEaH0+zUGx4="
     },
     "@types/q": {
       "version": "1.5.4",
diff --git a/web_src/package.json b/web_src/package.json
index 05178d4..c949393 100644
--- a/web_src/package.json
+++ b/web_src/package.json
@@ -10,7 +10,7 @@
     "build": "node build/build.js"
   },
   "dependencies": {
-    "@liveqing/liveplayer": "^1.9.6",
+    "@easydarwin/easywasmplayer": "^4.0.7",
     "axios": "^0.19.2",
     "core-js": "^2.6.5",
     "echarts": "^4.7.0",
diff --git a/web_src/src/components/gb28181/devicePlayer.vue b/web_src/src/components/gb28181/devicePlayer.vue
index c87d0c4..8442a82 100644
--- a/web_src/src/components/gb28181/devicePlayer.vue
+++ b/web_src/src/components/gb28181/devicePlayer.vue
@@ -1,9 +1,11 @@
 <template>
 <div id="devicePlayer" v-loading="isLoging">
+    
     <el-dialog title="瑙嗛鎾斁" top="0" :close-on-click-modal="false" :visible.sync="showVideoDialog" :destroy-on-close="true" @close="close()">
-        <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></LivePlayer>
+        <!-- <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></LivePlayer> -->
+        <player ref="videoPlayer" :visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></player>
         <div id="shared" style="text-align: right; margin-top: 1rem;">
-            <el-tabs v-model="tabActiveName">
+            <el-tabs v-model="tabActiveName" @tab-click="tabHandleClick">
                 <el-tab-pane label="瀹炴椂瑙嗛" name="media">
                     <div style="margin-bottom: 0.5rem;">
                         <!--		<el-button type="primary" size="small" @click="playRecord(true, '')">鎾斁</el-button>-->
@@ -97,6 +99,32 @@
                         </div>
                     </div>
                 </el-tab-pane>
+                <el-tab-pane label="缂栫爜淇℃伅" name="codec" v-loading="tracksLoading">
+                    <p>
+                        鏃犳硶鎾斁鎴栬�呮病鏈夊0闊�?&nbsp&nbsp&nbsp璇曚竴璇�
+                        <el-button size="mini" type="primary" v-if="!coverPlaying" @click="coverPlay">杞爜鎾斁</el-button>
+                        <el-button size="mini" type="danger" v-if="coverPlaying" @click="convertStopClick">鍋滄杞爜</el-button>
+                    </p>
+                    <div class="trank" >
+                        <div v-for="(item, index) in tracks">
+                            <span >娴� {{index}}</span>
+                            <div class="trankInfo" v-if="item.codec_type == 0">
+                                <p>鏍煎紡: {{item.codec_id_name}}</p>
+                                <p>绫诲瀷: 瑙嗛</p>
+                                <p>鍒嗚鲸鐜�: {{item.width}} x {{item.height}}</p>
+                                <p>甯х巼: {{item.fps}}</p>
+                            </div>
+                            <div class="trankInfo" v-if="item.codec_type == 1">
+                                <p>鏍煎紡: {{item.codec_id_name}}</p>
+                                <p>绫诲瀷: 闊抽</p>
+                                <p>閲囨牱浣嶆暟: {{item.sample_bit}}</p>
+                                <p>閲囨牱鐜�: {{item.sample_rate}}</p>
+                            </div>
+                        </div>
+                        
+                    </div>
+
+                </el-tab-pane>
             </el-tabs>
         </div>
     </el-dialog>
@@ -104,12 +132,12 @@
 </template>
 
 <script>
-import LivePlayer from '@liveqing/liveplayer'
+import player from './player.vue'
 export default {
     name: 'devicePlayer',
     props: {},
     components: {
-        LivePlayer
+        player,
     },
     computed: {
         getPlayerShared: function () {
@@ -131,6 +159,7 @@
             },
             showVideoDialog: false,
             ssrc: '',
+            streamId: '',
             convertKey: '',
             deviceId: '',
             channelId: '',
@@ -148,20 +177,45 @@
             cruisingGroup: 0,
             scanSpeed: 100,
             scanGroup: 0,
+            tracks: [],
+            coverPlaying:false,
+            tracksLoading: false
         };
     },
     methods: {
+        tabHandleClick: function(tab, event) {
+            console.log(tab)
+            var that = this;
+            that.tracks = [];
+            that.tracksLoading = true;
+            if (tab.name == "codec") {
+                this.$axios({
+                    method: 'get',
+                    url: '/zlm/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app=rtp&stream='+ this.streamId
+                }).then(function (res) {
+                    that.tracksLoading = false;
+                    if (res.data.code == 0 && res.data.online) {
+                        that.tracks = res.data.tracks;
+                    }else{
+                        that.$message({
+                            showClose: true,
+                            message: '鑾峰彇缂栫爜淇℃伅澶辫触,',
+                            type: 'warning'
+                        });
+                    }
+                }).catch(function (e) {});
+            }
+        },
         openDialog: function (tab, deviceId, channelId, param) {
             this.tabActiveName = tab;
             this.channelId = channelId;
             this.deviceId = deviceId;
             this.ssrc = "";
+            this.streamId = "";
             this.videoUrl = ""
             if (!!this.$refs.videoPlayer) {
                 this.$refs.videoPlayer.pause();
             }
-
-
             switch (tab) {
                 case "media":
                     this.play(param.streamInfo, param.hasAudio)
@@ -180,85 +234,56 @@
             console.log(val)
         },
         play: function (streamInfo, hasAudio) {
+            
             this.hasaudio = hasAudio;
-            var that = this;
-            that.isLoging = false;
-            if (!!streamInfo.tracks && streamInfo.tracks.length > 0 ) {
-                for (let i = 0; i < streamInfo.tracks.length; i++) {
-                  if (streamInfo.tracks[i].codec_type == 0 && streamInfo.tracks[i].codec_id_name != "CodecH264") { // 鍒ゆ柇涓篐265瑙嗛
-                    that.coverPlay(streamInfo, streamInfo.tracks[i].codec_id_name, ()=>{
-                      that.close();
-                      return;
-                    })
-                  }else if (streamInfo.tracks[i].codec_type == 1 && streamInfo.tracks[i].codec_id_name != "CodecAAC") {
-                    that.coverPlay(streamInfo, streamInfo.tracks[i].codec_id_name, ()=>{
-                      that.playFromStreamInfo(false. streamInfo)
-                    })
-                  }else if (streamInfo.tracks[i].codec_type == 1 && streamInfo.tracks[i].codec_id_name == "CodecAAC") {
-                    that.playFromStreamInfo(true, streamInfo)
-                  }else {
-                    that.playFromStreamInfo(false, streamInfo)
-                  }
-                }
-            }else {
-              that.playFromStreamInfo(false, streamInfo)
-            }
+            this.isLoging = false;
+            this.videoUrl = streamInfo.ws_flv;
+            this.ssrc = streamInfo.ssrc;
+            this.streamId = streamInfo.streamId;
+            this.playFromStreamInfo(false, streamInfo)
         },
-        coverPlay: function (streamInfo, codec_id_name, catchcallback) {
-          var that = this;
-
-          that.$confirm(codec_id_name + ' 缂栫爜鏍煎紡涓嶆敮鎸佹挱鏀�, 鏄惁杞爜鎾斁?', '鎻愮ず', {
-              confirmButtonText: '纭畾',
-              cancelButtonText: '鍙栨秷',
-              type: 'warning'
-            }).then(() => {
-              that.isLoging = true;
-              that.$axios({
+        coverPlay: function () {
+            var that = this;
+            this.coverPlaying = true;
+            this.$refs.videoPlayer.pause()
+            that.$axios({
                 method: 'post',
-                url: '/api/play/' + streamInfo.ssrc + '/convert'
-              }).then(function (res) {
-                if (res.data.code == 0) {
-                  streamInfo.ws_flv = res.data.ws_flv;
-                  that.convertKey = res.data.key;
-                  setTimeout(()=>{
-                    that.isLoging = false;
-                    that.playFromStreamInfo(false, streamInfo);
-                  }, 2000)
-                } else {
-                  that.isLoging = false;
-                  that.$message({
-                    showClose: true,
-                    message: '杞爜澶辫触',
-                    type: 'error'
-                  });
-                }
-              }).catch(function (e) {
-                that.$message({
-                  showClose: true,
-                  message: '鎾斁閿欒',
-                  type: 'error'
+                url: '/api/play/' + that.ssrc + '/convert'
+                }).then(function (res) {
+                    if (res.data.code == 0) {
+                        that.convertKey = res.data.key;
+                        setTimeout(()=>{
+                            that.isLoging = false;
+                            that.playFromStreamInfo(false, res.data.data);
+                        }, 2000)
+                    } else {
+                        that.isLoging = false;
+                        that.coverPlaying = false;
+                        that.$message({
+                            showClose: true,
+                            message: '杞爜澶辫触',
+                            type: 'error'
+                        });
+                    }
+                }).catch(function (e) {
+                    console.log(e)
+                    that.coverPlaying = false;
+                    that.$message({
+                        showClose: true,
+                        message: '鎾斁閿欒',
+                        type: 'error'
+                    });
                 });
-              });
-            }).catch(function (e) {
-                if (catchcallback)catchcallback()
+        },
+        convertStopClick: function() {
+            this.convertStop(()=>{
+                this.$refs.videoPlayer.play(this.videoUrl)
             });
         },
-        playFromStreamInfo: function (realHasAudio, streamInfo) {
-          this.videoUrl = streamInfo.ws_flv;
-          this.showVideoDialog = true;
-          this.hasaudio = realHasAudio && this.hasaudio;
-          this.ssrc = streamInfo.ssrc;
-          console.log(this.ssrc);
-        },
-        close: function () {
-            console.log('鍏抽棴瑙嗛');
-            if (!this.$refs.videoPlayer){
-              this.$refs.videoPlayer.pause();
-            }
-            this.videoUrl = '';
-            this.showVideoDialog = false;
-            if (this.convertKey != '') {
-              this.$axios({
+        convertStop: function(callback) {
+            var that = this;
+            that.$refs.videoPlayer.pause()
+            this.$axios({
                 method: 'post',
                 url: '/api/play/convert/stop/' + this.convertKey
               }).then(function (res) {
@@ -267,12 +292,36 @@
                 }else {
                   console.error(res.data.msg)
                 }
+                 if (callback )callback();
               }).catch(function (e) {});
-            }
-          this.convertKey = ''
+            that.coverPlaying = false;
+            that.convertKey = "";
+            // if (callback )callback();
         },
+
+        playFromStreamInfo: function (realHasAudio, streamInfo) {
+          this.showVideoDialog = true;
+          this.hasaudio = realHasAudio && this.hasaudio;
+          this.$refs.videoPlayer.play(streamInfo.ws_flv)
+        },
+        close: function () {
+            console.log('鍏抽棴瑙嗛');
+            if (!!this.$refs.videoPlayer){
+              this.$refs.videoPlayer.pause();
+            }
+            this.videoUrl = '';
+            this.coverPlaying = false;
+            this.showVideoDialog = false;
+            if (this.convertKey != '') {
+              this.convertStop();
+            }
+            this.convertKey = ''
+        },
+        
         copySharedInfo: function (data) {
             console.log('澶嶅埗鍐呭锛�' + data);
+            this.coverPlaying = false;
+            this.tracks = []
             let _this = this;
             this.$copyText(data).then(
                 function (e) {
@@ -602,4 +651,15 @@
 .control-bottom .fa {
     transform: rotate(-45deg) translateY(7px);
 }
+.trank {
+    width: 80%;
+    height: 180px;
+    text-align: left;
+    padding: 0 10%;
+    overflow: auto;
+}
+.trankInfo {
+    width: 80%;
+    padding: 0 10%;
+}
 </style>
diff --git a/web_src/src/components/gb28181/player.vue b/web_src/src/components/gb28181/player.vue
new file mode 100644
index 0000000..0abf5c0
--- /dev/null
+++ b/web_src/src/components/gb28181/player.vue
@@ -0,0 +1,57 @@
+<template>
+    <div id="player">
+        <div id="easyplayer"></div>   
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'player',
+    data() {
+        return {
+            easyPlayer: null
+        };
+    },
+    props: ['videoUrl', 'error', 'hasaudio'],
+    mounted () {
+       this.$nextTick(() =>{
+           console.log("鍒濆鍖栨椂鐨勫湴鍧�涓�: " + this.videoUrl)
+            this.easyPlayer = new WasmPlayer(null, 'easyplayer', this.eventcallbacK)
+            this.easyPlayer.play(this.videoUrl, 1)
+        })
+    },
+    watch:{
+        videoUrl(newData, oldData){
+            this.easyPlayer.destroy()
+            this.easyPlayer = new WasmPlayer(null, 'easyplayer', this.eventcallbacK)
+            this.easyPlayer.play(newData, 1)
+        },
+        immediate:true
+    },
+    methods: {
+        play: function (url) {
+            this.easyPlayer = new WasmPlayer(null, 'easyplayer', this.eventcallbacK)
+            this.easyPlayer.play(url, 1)
+        },
+        pause: function () {
+            this.easyPlayer.destroy();
+        },
+        eventcallbacK: function(type, message) {
+            console.log("player 浜嬩欢鍥炶皟")
+            console.log(type)
+            console.log(message)
+        }
+    },
+}
+</script>
+
+<style>
+    .LodingTitle {
+        min-width: 70px;
+    }
+    /* 闅愯棌logo */
+    /* .iconqingxiLOGO {
+        display: none !important;
+    } */
+    
+</style>
\ No newline at end of file
diff --git a/web_src/src/components/videoList.vue b/web_src/src/components/videoList.vue
index ebf3ad0..ad2f701 100644
--- a/web_src/src/components/videoList.vue
+++ b/web_src/src/components/videoList.vue
@@ -73,12 +73,10 @@
 </template>
 
 <script>
-	 import devicePlayer from './gb28181/devicePlayer.vue'
 	 import uiHeader from './UiHeader.vue'
 	export default {
 		name: 'app',
 		components: {
-			devicePlayer,
 			uiHeader
 		},
 		data() {
diff --git a/web_src/src/router/index.js b/web_src/src/router/index.js
index 73a5781..658da4e 100644
--- a/web_src/src/router/index.js
+++ b/web_src/src/router/index.js
@@ -35,7 +35,7 @@
       path: '/channelList/:deviceId/:parentChannelId/:count/:page',
       name: 'channelList',
       component: channelList,
-    },,
+    },
     {
       path: '/parentPlatformList/:count/:page',
       name: 'parentPlatformList',

--
Gitblit v1.8.0