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 6e876be1..0e7da448 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java +++ b/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; } } 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 3a971a79..481bb43b 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 @@ -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(); 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 0dfcdb0f..774cd60d 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 @@ -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(); } } 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 2d6b8e77..22ebe521 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 @@ -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"); diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java index fd0a6656..8381738c 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java +++ b/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); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java index 272912f2..c3a18b79 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java +++ b/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; + } } 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 1acd15ce..5ca8b1c4 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 @@ -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 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 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 { } } } + + + } 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 b7d61015..64bcf344 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 @@ -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 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)); } 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 d2644f3b..8d845b1c 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java +++ b/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") diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue index 5cd108e9..7a1e0e28 100644 --- a/web_src/src/components/channelList.vue +++ b/web_src/src/components/channelList.vue @@ -35,8 +35,16 @@ - - + + + + +