Browse Source

离在线状态样式修改
修复未回复200ok导致catalog一直发送的bug
修改点播接口未收到视频后回复

648540858 5 years ago
parent
commit
d4ae8194eb

+ 38 - 20
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java

@@ -3,11 +3,13 @@ package com.genersoft.iot.vmp.common;
 public class StreamInfo {
 
     private String ssrc;
+    private String deviceID;
+    private String cahnnelId;
     private String flv;
-    private String WS_FLV;
-    private String RTMP;
-    private String HLS;
-    private String RTSP;
+    private String ws_flv;
+    private String rtmp;
+    private String hls;
+    private String rtsp;
 
     public String getSsrc() {
         return ssrc;
@@ -25,35 +27,51 @@ public class StreamInfo {
         this.flv = flv;
     }
 
-    public String getWS_FLV() {
-        return WS_FLV;
+    public String getWs_flv() {
+        return ws_flv;
     }
 
-    public void setWS_FLV(String WS_FLV) {
-        this.WS_FLV = WS_FLV;
+    public void setWs_flv(String ws_flv) {
+        this.ws_flv = ws_flv;
     }
 
-    public String getRTMP() {
-        return RTMP;
+    public String getRtmp() {
+        return rtmp;
     }
 
-    public void setRTMP(String RTMP) {
-        this.RTMP = RTMP;
+    public void setRtmp(String rtmp) {
+        this.rtmp = rtmp;
     }
 
-    public String getHLS() {
-        return HLS;
+    public String getHls() {
+        return hls;
     }
 
-    public void setHLS(String HLS) {
-        this.HLS = HLS;
+    public void setHls(String hls) {
+        this.hls = hls;
     }
 
-    public String getRTSP() {
-        return RTSP;
+    public String getRtsp() {
+        return rtsp;
     }
 
-    public void setRTSP(String RTSP) {
-        this.RTSP = RTSP;
+    public void setRtsp(String rtsp) {
+        this.rtsp = rtsp;
+    }
+
+    public String getDeviceID() {
+        return deviceID;
+    }
+
+    public void setDeviceID(String deviceID) {
+        this.deviceID = deviceID;
+    }
+
+    public String getCahnnelId() {
+        return cahnnelId;
+    }
+
+    public void setCahnnelId(String cahnnelId) {
+        this.cahnnelId = cahnnelId;
     }
 }

+ 9 - 8
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java

@@ -242,14 +242,15 @@ public class SIPCommander implements ISIPCommander {
 			StreamInfo streamInfo = new StreamInfo();
 			streamInfo.setSsrc(ssrc);
 //			String streamId = Integer.toHexString(Integer.parseInt(streamInfo.getSsrc()));
-			String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); // ZLM 要求大写且首位补零
-			streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
-			streamInfo.setWS_FLV(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
-			streamInfo.setRTMP(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtmpPort(), streamId));
-			streamInfo.setHLS(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
-			streamInfo.setRTSP(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtspPort(), streamId));
-
-			storager.startPlay(device.getDeviceId(), channelId, streamInfo);
+//			String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); // ZLM 要求大写且首位补零
+//			streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
+//			streamInfo.setWS_FLV(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
+//			streamInfo.setRTMP(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtmpPort(), streamId));
+//			streamInfo.setHLS(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
+//			streamInfo.setRTSP(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtspPort(), streamId));
+			streamInfo.setCahnnelId(channelId);
+			streamInfo.setDeviceID(device.getDeviceId());
+			storager.startPlay(streamInfo);
 			return streamInfo;
 		} catch ( SipException | ParseException | InvalidArgumentException e) {
 			e.printStackTrace();

+ 4 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java

@@ -210,8 +210,11 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 				msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG);
 				msg.setData(device);
 				deferredResultHolder.invokeResult(msg);
+
+				// 回复200
+				responseAck(evt);
 			}
-		} catch (DocumentException e) {
+		} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
 			e.printStackTrace();
 		}
 	}

+ 32 - 4
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java

@@ -1,11 +1,13 @@
 package com.genersoft.iot.vmp.media.zlm;
 
 import java.math.BigInteger;
+import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.List;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
+import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.MediaServerConfig;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.utils.IpUtil;
@@ -35,7 +37,8 @@ import javax.servlet.http.HttpServletRequest;
 public class ZLMHttpHookListener {
 
 	private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class);
-	
+
+
 	@Autowired
 	private SIPCommander cmder;
 
@@ -54,7 +57,7 @@ public class ZLMHttpHookListener {
 			logger.debug("ZLM HOOK on_flow_report API调用,参数:" + json.toString());
 		}
 		// TODO Auto-generated method stub
-		
+
 		
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
@@ -113,6 +116,21 @@ public class ZLMHttpHookListener {
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_publish API调用,参数:" + json.toString());
 		}
+		String app = json.getString("app");
+		String streamId = json.getString("id");
+//		String ssrc = String.format("%10d", Integer.parseInt(streamId, 16)); // ZLM 要求大写且首位补零
+		String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
+		StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
+		if ("rtp".equals(app) && streamInfo != null ) {
+			MediaServerConfig mediaInfo = storager.getMediaInfo();
+			streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
+			streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
+			streamInfo.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtmpPort(), streamId));
+			streamInfo.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
+			streamInfo.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtspPort(), streamId));
+			storager.startPlay(streamInfo);
+		}
+
 		// TODO Auto-generated method stub
 		
 		JSONObject ret = new JSONObject();
@@ -213,8 +231,18 @@ public class ZLMHttpHookListener {
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_stream_changed API调用,参数:" + json.toString());
 		}
-		// TODO Auto-generated method stub
-		
+		// 流消失移除redis play
+		String app = json.getString("app");
+		String streamId = json.getString("stream");
+		boolean regist = json.getBoolean("regist");
+//		String ssrc = String.format("%10d", Integer.parseInt(streamId, 16)); // ZLM 要求大写且首位补零
+		String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
+		StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
+		if ("rtp".equals(app) && !regist ) {
+			storager.stopPlay(streamInfo);
+		}
+
+
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
 		ret.put("msg", "success");

+ 7 - 9
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java

@@ -136,30 +136,24 @@ public interface IVideoManagerStorager {
 	/**
 	 * 开始播放时将流存入
 	 *
-	 * @param deviceId 设备ID
-	 * @param channelId 通道ID
 	 * @param stream 流信息
 	 * @return
 	 */
-	public boolean startPlay(String deviceId, String channelId, StreamInfo stream);
+	public boolean startPlay(StreamInfo stream);
 
 	/**
 	 * 停止播放时删除
 	 *
-	 * @param deviceId 设备ID
-	 * @param channelId 通道ID
 	 * @return
 	 */
-	public boolean stopPlay(String deviceId, String channelId);
+	public boolean stopPlay(StreamInfo streamInfo);
 
 	/**
 	 * 查找视频流
 	 *
-	 * @param deviceId 设备ID
-	 * @param channelId 通道ID
 	 * @return
 	 */
-	public StreamInfo queryPlay(String deviceId, String channelId);
+	public StreamInfo queryPlay(StreamInfo streamInfo);
 
 	/**
 	 * 查询子设备
@@ -182,4 +176,8 @@ public interface IVideoManagerStorager {
 	 * @param deviceId
 	 */
 	void cleanChannelsForDevice(String deviceId);
+
+	StreamInfo queryPlayBySSRC(String ssrc);
+
+	StreamInfo queryPlayByDevice(String deviceId, String code);
 }

+ 17 - 7
src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java

@@ -148,17 +148,12 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
 	}
 
 	@Override
-	public boolean startPlay(String deviceId, String channelId, StreamInfo stream) {
+	public boolean stopPlay(StreamInfo streamInfo) {
 		return false;
 	}
 
 	@Override
-	public boolean stopPlay(String deviceId, String channelId) {
-		return false;
-	}
-
-	@Override
-	public StreamInfo queryPlay(String deviceId, String channelId) {
+	public StreamInfo queryPlay(StreamInfo streamInfo) {
 		return null;
 	}
 
@@ -176,4 +171,19 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
 	public void cleanChannelsForDevice(String deviceId) {
 
 	}
+
+	@Override
+	public boolean startPlay(StreamInfo stream) {
+		return false;
+	}
+
+	@Override
+	public StreamInfo queryPlayBySSRC(String ssrc) {
+		return null;
+	}
+
+	@Override
+	public StreamInfo queryPlayByDevice(String deviceId, String code) {
+		return null;
+	}
 }

+ 29 - 13
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java

@@ -329,40 +329,53 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 	/**
 	 * 开始播放时将流存入redis
 	 *
-	 * @param deviceId 设备ID
-	 * @param channelId 通道ID
 	 * @return
 	 */
 	@Override
-	public boolean startPlay(String deviceId, String channelId, StreamInfo stream) {
-		return redis.set(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId),
+	public boolean startPlay(StreamInfo stream) {
+		return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()),
 				stream);
 	}
 
 	/**
 	 * 停止播放时从redis删除
 	 *
-	 * @param deviceId 设备ID
-	 * @param channelId 通道ID
 	 * @return
 	 */
 	@Override
-	public boolean stopPlay(String deviceId, String channelId) {
-		return redis.del(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId));
+	public boolean stopPlay(StreamInfo streamInfo) {
+		return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
+				streamInfo.getSsrc(),
+				streamInfo.getDeviceID(),
+				streamInfo.getCahnnelId()));
 	}
 
 	/**
 	 * 查询播放列表
-	 * @param deviceId 设备ID
-	 * @param channelId 通道ID
 	 * @return
 	 */
 	@Override
-	public StreamInfo queryPlay(String deviceId, String channelId) {
-		return (StreamInfo)redis.get(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId));
+	public StreamInfo queryPlay(StreamInfo streamInfo) {
+		return (StreamInfo)redis.get(String.format("%S_%s_%s_%s",
+				VideoManagerConstants.PLAYER_PREFIX,
+				streamInfo.getSsrc(),
+				streamInfo.getDeviceID(),
+				streamInfo.getCahnnelId()));
+	}
+	@Override
+	public StreamInfo queryPlayBySSRC(String ssrc) {
+		List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
+		if (playLeys.size() == 0) return null;
+		return (StreamInfo)redis.get(playLeys.get(0).toString());
 	}
 
-
+	@Override
+	public StreamInfo queryPlayByDevice(String deviceId, String code) {
+		List<Object> playLeys = redis.keys(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
+				deviceId,
+				code));
+		return (StreamInfo)redis.get(playLeys.get(0).toString());
+	}
 
 	/**
 	 * 更新流媒体信息
@@ -423,4 +436,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 			}
 		}
 	}
+
+
+
 }

+ 14 - 2
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java

@@ -37,7 +37,18 @@ public class PlayController {
 		
 		Device device = storager.queryVideoDevice(deviceId);
 		StreamInfo streamInfo = cmder.playStreamCmd(device, channelId);
-		
+		// 等待推流, TODO 默认超时15s
+
+		long startTime = System.currentTimeMillis();
+		while (storager.queryPlay(streamInfo) == null || storager.queryPlay(streamInfo).getFlv() == null) {
+			try {
+				if (System.currentTimeMillis() - startTime > 15 * 1000)
+				Thread.sleep(200);
+			} catch (InterruptedException e) {
+				e.printStackTrace();
+			}
+		}
+		streamInfo = storager.queryPlay(streamInfo);
 		if (logger.isDebugEnabled()) {
 			logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",deviceId, channelId));
 			logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc())));
@@ -55,7 +66,8 @@ public class PlayController {
 	public ResponseEntity<String> playStop(@PathVariable String ssrc){
 		
 		cmder.streamByeCmd(ssrc);
-		
+		StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
+		storager.stopPlay(streamInfo);
 		if (logger.isDebugEnabled()) {
 			logger.debug(String.format("设备预览停止API调用,ssrc:%s", ssrc));
 		}

+ 7 - 8
src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java

@@ -70,7 +70,7 @@ public class ApiStreamController {
             return result;
         }
         // 查询是否已经在播放
-        StreamInfo streamInfo = storager.queryPlay(device.getDeviceId(), code);
+        StreamInfo streamInfo = storager.queryPlayByDevice(device.getDeviceId(), code);
         if (streamInfo == null) streamInfo = cmder.playStreamCmd(device, code);
 
         if (logger.isDebugEnabled()) {
@@ -86,10 +86,10 @@ public class ApiStreamController {
             result.put("ChannelName", deviceChannel.getName());
             result.put("ChannelCustomName ", "");
             result.put("FLV ", streamInfo.getFlv());
-            result.put("WS_FLV ", streamInfo.getWS_FLV());
-            result.put("RTMP", streamInfo.getRTMP());
-            result.put("HLS", streamInfo.getHLS());
-            result.put("RTSP", streamInfo.getRTSP());
+            result.put("WS_FLV ", streamInfo.getWs_flv());
+            result.put("RTMP", streamInfo.getRtmp());
+            result.put("HLS", streamInfo.getHls());
+            result.put("RTSP", streamInfo.getRtsp());
             result.put("CDN", "");
             result.put("SnapURL", "");
             result.put("Transport", device.getTransport());
@@ -135,14 +135,14 @@ public class ApiStreamController {
                              @RequestParam(required = false)String check_outputs
 
     ){
-        StreamInfo streamInfo = storager.queryPlay(serial, code);
+        StreamInfo streamInfo = storager.queryPlayByDevice(serial, code);
         if (streamInfo == null) {
             JSONObject result = new JSONObject();
             result.put("error","未找到流信息");
             return result;
         }
         cmder.streamByeCmd(streamInfo.getSsrc());
-        storager.stopPlay(serial, code);
+        storager.stopPlay(streamInfo);
         return null;
     }
 
@@ -151,7 +151,6 @@ public class ApiStreamController {
      * @param serial 设备编号
      * @param channel 通道序号
      * @param code 通道国标编号
-     * @param check_outputs
      * @return
      */
     @RequestMapping(value = "/touch")

+ 18 - 5
web_src/src/components/channelList.vue

@@ -35,8 +35,16 @@
 						</el-table-column>
 						<el-table-column prop="subCount" label="子节点数">
 						</el-table-column>
-						<el-table-column prop="ptztypeText" label="云台类型">
-						</el-table-column>
+          <el-table-column label="状态" width="180" align="center">
+            <template slot-scope="scope">
+              <div slot="reference" class="name-wrapper">
+                <el-tag size="medium" v-if="scope.row.status == 1">在线</el-tag>
+                <el-tag size="medium" type="info" v-if="scope.row.status == 0">离线</el-tag>
+              </div>
+            </template>
+          </el-table-column>
+            <el-table-column prop="ptztypeText" label="云台类型">
+            </el-table-column>
 						<el-table-column label="操作" width="240" align="center" fixed="right">
 							<template slot-scope="scope">
 								<el-button size="mini" icon="el-icon-video-play" v-if="scope.row.parental == 0" @click="sendDevicePush(scope.row)">预览视频</el-button>
@@ -58,17 +66,20 @@
 
 			</el-main>
 		</el-container>
+    <Loading v-if="isLoging" marginTop="-50%"></Loading>
 	</div>
 </template>
 
 <script>
 	 import devicePlayer from './gb28181/devicePlayer.vue'
 	 import uiHeader from './UiHeader.vue'
+   import Loading from './Loading.vue'
 	export default {
 		name: 'channelList',
 		components: {
 			devicePlayer,
-			uiHeader
+			uiHeader,
+      Loading
 		},
 		data() {
 			return {
@@ -85,7 +96,8 @@
 				currentPage: parseInt(this.$route.params.page),
 				count: parseInt(this.$route.params.count),
 				total:0,
-				beforeUrl:"/videoList"
+				beforeUrl:"/videoList",
+        isLoging: false
 			};
 		},
 
@@ -182,7 +194,7 @@
 			//通知设备上传媒体流
 			sendDevicePush: function(itemData) {
 				let deviceId = this.deviceId;
-
+        this.isLoging = true;
 				let channelId = itemData.channelId;
 				console.log("通知设备推流1:" + deviceId + " : " + channelId);
 				let that = this;
@@ -191,6 +203,7 @@
 					url: '/api/play/' + deviceId + '/' + channelId
 				}).then(function(res) {
 					let ssrc = res.data.ssrc;
+          that.isLoging = false
 					that.$refs.devicePlayer.play(res.data,deviceId,channelId);
 				}).catch(function(e) {
 				});

+ 1 - 0
web_src/src/components/gb28181/devicePlayer.vue

@@ -115,6 +115,7 @@
 				deviceId: '',
 				channelId: '',
 				tabActiveName: 'media'
+
 			};
 		},
 		methods: {

+ 3 - 3
web_src/src/components/videoList.vue

@@ -1,7 +1,6 @@
 <template>
 	<div id="app">
 		<el-container>
-
 			<el-header>
 				<uiHeader></uiHeader>
 			</el-header>
@@ -37,14 +36,15 @@
 					<el-table-column label="状态" width="180" align="center">
 						<template slot-scope="scope">
 							<div slot="reference" class="name-wrapper">
-								<el-tag size="medium">{{ scope.row.online==1?'在线' :'离线'}}</el-tag>
+								<el-tag size="medium" v-if="scope.row.online == 1">在线</el-tag>
+								<el-tag size="medium" type="info" v-if="scope.row.online == 0">离线</el-tag>
 							</div>
 						</template>
 					</el-table-column>
 
 					<el-table-column label="操作" width="240" align="center" fixed="right">
 						<template slot-scope="scope">
-							<el-button size="mini" icon="el-icon-refresh"  @click="refDevice(scope.row)">刷新</el-button>
+							<el-button size="mini" icon="el-icon-refresh"  @click="refDevice(scope.row)">刷新通道</el-button>
 							<el-button size="mini" icon="el-icon-s-open"  type="primary" @click="showChannelList(scope.row)">查看通道</el-button>
 						</template>
 					</el-table-column>