Merge remote-tracking branch 'origin/wvp-28181-2.0' into wvp-28181-2.0
New file |
| | |
| | | --- |
| | | name: "[ 新功能 ]" |
| | | about: 新功能 |
| | | title: '' |
| | | labels: '' |
| | | assignees: '' |
| | | |
| | | --- |
| | | |
| | | |
New file |
| | |
| | | --- |
| | | name: "[ BUG ] " |
| | | about: Create a report to help us improve |
| | | title: '' |
| | | labels: '' |
| | | assignees: '' |
| | | |
| | | --- |
| | | |
| | | **描述错误** |
| | | 描述下您遇到的问题 |
| | | |
| | | **如何复现** |
| | | 有明确复现步骤的问题会很容易被解决 |
| | | |
| | | **预期行为** |
| | | 清晰简洁的描述您期望发生的事情 |
| | | |
| | | **截图** |
| | | |
| | | |
| | | **环境信息:** |
| | | - 1. 部署方式 wvp-pro docker / zlm(docker) + 编译wvp-pro/ wvp-prp + zlm都是编译部署/ |
| | | - 2. 部署环境 windows / ubuntu/ centos ... |
| | | - 3. 端口开放情况 |
| | | - 4. 是否是公网部署 |
| | | - 5. 是否使用https |
| | | - 6. 方便的话提供下使用的设备品牌或平台 |
| | | - 7. 你做过哪些尝试 |
| | |
| | | public static final String PLAYER_PREFIX = "VMP_PLAYER_";
|
| | |
|
| | | public static final String PLAY_BLACK_PREFIX = "VMP_PLAYBACK_";
|
| | | public static final String DOWNLOAD_PREFIX = "VMP_DOWNLOAD_";
|
| | |
|
| | | public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_PLATFORM_KEEPLIVE_";
|
| | |
|
| | |
| | |
|
| | | private String channelId;
|
| | |
|
| | | private String sn;
|
| | |
|
| | | private String name;
|
| | |
|
| | | private int sumNum;
|
| | |
| | | public void setChannelId(String channelId) {
|
| | | this.channelId = channelId;
|
| | | }
|
| | |
|
| | | public String getSn() {
|
| | | return sn;
|
| | | }
|
| | |
|
| | | public void setSn(String sn) {
|
| | | this.sn = sn;
|
| | | }
|
| | | }
|
| | |
| | | // 自然顺序排序, 元素进行升序排列 |
| | | this.recordInfo.getRecordList().sort(Comparator.naturalOrder()); |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setKey(DeferredResultHolder.CALLBACK_CMD_RECORDINFO + recordInfo.getDeviceId() + recordInfo.getChannelId()); |
| | | msg.setKey(DeferredResultHolder.CALLBACK_CMD_RECORDINFO + recordInfo.getDeviceId() + recordInfo.getSn()); |
| | | msg.setData(recordInfo); |
| | | deferredResultHolder.invokeAllResult(msg); |
| | | logger.info("处理完成,返回结果"); |
| | |
| | |
|
| | | public static final String CALLBACK_CMD_PLAY = "CALLBACK_PLAY";
|
| | |
|
| | | public static final String CALLBACK_CMD_PLAYBACK = "CALLBACK_PLAY";
|
| | |
|
| | | public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD";
|
| | |
|
| | | public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
|
| | |
|
| | | public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION";
|
| | |
| | | * @param device 视频设备
|
| | | * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
|
| | | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
| | | * @param sn
|
| | | */
|
| | | boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, SipSubscribe.Event errorEvent);
|
| | | boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, SipSubscribe.Event errorEvent);
|
| | |
|
| | | /**
|
| | | * 查询报警信息
|
| | |
| | | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
| | | */
|
| | | @Override
|
| | | public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, SipSubscribe.Event errorEvent) {
|
| | | |
| | | public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, SipSubscribe.Event errorEvent) {
|
| | |
|
| | |
|
| | | try {
|
| | | StringBuffer recordInfoXml = new StringBuffer(200);
|
| | | recordInfoXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
|
| | | recordInfoXml.append("<Query>\r\n");
|
| | | recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");
|
| | | recordInfoXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
|
| | | recordInfoXml.append("<SN>" + sn + "</SN>\r\n");
|
| | | recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
|
| | | recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
|
| | | recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
|
| | |
| | | String uuid = UUID.randomUUID().toString().replace("-", ""); |
| | | RecordInfo recordInfo = new RecordInfo(); |
| | | Element rootElement = getRootElement(evt); |
| | | Element deviceIdElement = rootElement.element("DeviceID"); |
| | | String channelId = deviceIdElement.getText().toString(); |
| | | String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + channelId; |
| | | String sn = getText(rootElement, "SN"); |
| | | String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn; |
| | | if (device != null ) { |
| | | rootElement = getRootElement(evt, device.getCharset()); |
| | | } |
| | | recordInfo.setDeviceId(deviceId); |
| | | recordInfo.setChannelId(channelId); |
| | | recordInfo.setSn(sn); |
| | | recordInfo.setName(getText(rootElement, "Name")); |
| | | if (getText(rootElement, "SumNum")== null || getText(rootElement, "SumNum") =="") { |
| | | recordInfo.setSumNum(0); |
| | | } else { |
| | | recordInfo.setSumNum(Integer.parseInt(getText(rootElement, "SumNum"))); |
| | | } |
| | | String sn = getText(rootElement, "SN"); |
| | | |
| | | Element recordListElement = rootElement.element("RecordList"); |
| | | if (recordListElement == null || recordInfo.getSumNum() == 0) { |
| | | logger.info("无录像数据"); |
| | |
| | | rootElement = getRootElement(evt, device.getCharset()); |
| | | String uuid = UUID.randomUUID().toString().replace("-", ""); |
| | | RecordInfo recordInfo = new RecordInfo(); |
| | | Element deviceIdElement = rootElement.element("DeviceID"); |
| | | String channelId = deviceIdElement.getText(); |
| | | String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + device.getDeviceId() + channelId; |
| | | String sn = getText(rootElement, "SN"); |
| | | String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + device.getDeviceId() + sn; |
| | | recordInfo.setDeviceId(device.getDeviceId()); |
| | | recordInfo.setChannelId(channelId); |
| | | recordInfo.setSn(sn); |
| | | recordInfo.setName(getText(rootElement, "Name")); |
| | | if (getText(rootElement, "SumNum") == null || getText(rootElement, "SumNum") == "") { |
| | | recordInfo.setSumNum(0); |
| | | } else { |
| | | recordInfo.setSumNum(Integer.parseInt(getText(rootElement, "SumNum"))); |
| | | } |
| | | String sn = getText(rootElement, "SN"); |
| | | Element recordListElement = rootElement.element("RecordList"); |
| | | if (recordListElement == null || recordInfo.getSumNum() == 0) { |
| | | logger.info("无录像数据"); |
| | |
| | | subscribe.response(mediaInfo, json);
|
| | | }
|
| | | }
|
| | | String app = json.getString("app");
|
| | | String stream = json.getString("stream");
|
| | | StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(stream);
|
| | | JSONObject ret = new JSONObject();
|
| | | // 录像回放时不进行录像下载
|
| | | if (streamInfo != null) {
|
| | | ret.put("enableMP4", false);
|
| | | }else {
|
| | | ret.put("enableMP4", userSetup.isRecordPushLive());
|
| | | }
|
| | | ret.put("code", 0);
|
| | | ret.put("msg", "success");
|
| | | ret.put("enableHls", true);
|
| | | ret.put("enableMP4", userSetup.isRecordPushLive());
|
| | | ret.put("enableRtxp", true);
|
| | | return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
|
| | | }
|
| | |
|
| | |
| | | String mediaServerId = json.getString("mediaServerId");
|
| | | String streamId = json.getString("stream");
|
| | | String app = json.getString("app");
|
| | |
|
| | | // TODO 如果在给上级推流,也不停止。
|
| | | JSONObject ret = new JSONObject();
|
| | | ret.put("code", 0);
|
| | | if ("rtp".equals(app)){
|
| | | JSONObject ret = new JSONObject();
|
| | | ret.put("code", 0);
|
| | | ret.put("close", true);
|
| | | StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(streamId);
|
| | | if (streamInfoForPlayCatch != null) {
|
| | | // 如果在给上级推流,也不停止。
|
| | | if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) {
|
| | | ret.put("close", false);
|
| | | } else {
|
| | |
| | | if (streamInfoForPlayBackCatch != null) {
|
| | | cmder.streamByeCmd(streamInfoForPlayBackCatch.getDeviceID(), streamInfoForPlayBackCatch.getChannelId());
|
| | | redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch);
|
| | | }else {
|
| | | StreamInfo streamInfoForDownload = redisCatchStorage.queryDownloadByStreamId(streamId);
|
| | | // 进行录像下载时无人观看不断流
|
| | | if (streamInfoForDownload != null) {
|
| | | ret.put("close", false);
|
| | | }
|
| | | }
|
| | | }
|
| | | MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
| | |
| | | }
|
| | | return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
|
| | | }else {
|
| | | JSONObject ret = new JSONObject();
|
| | | ret.put("code", 0);
|
| | | StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, streamId);
|
| | | if (streamProxyItem != null && streamProxyItem.isEnable_remove_none_reader()) {
|
| | | ret.put("close", true);
|
| | |
| | | PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent); |
| | | |
| | | MediaServerItem getNewMediaServerItem(Device device); |
| | | |
| | | void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String toString); |
| | | } |
| | |
| | | import org.springframework.util.ResourceUtils; |
| | | import org.springframework.web.context.request.async.DeferredResult; |
| | | |
| | | import javax.sip.DialogTerminatedEvent; |
| | | import javax.sip.ResponseEvent; |
| | | import javax.sip.TimeoutEvent; |
| | | import javax.sip.TransactionTerminatedEvent; |
| | | import javax.sip.message.Response; |
| | | import java.io.FileNotFoundException; |
| | | import java.util.Objects; |
| | | import java.util.UUID; |
| | |
| | | return mediaServerItem; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void onPublishHandlerForPlayBack(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) { |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId); |
| | | msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId); |
| | | msg.setId(uuid); |
| | | StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid); |
| | | if (streamInfo != null) { |
| | | redisCatchStorage.startPlayback(streamInfo); |
| | | msg.setData(JSON.toJSONString(streamInfo)); |
| | | resultHolder.invokeResult(msg); |
| | | } else { |
| | | logger.warn("设备回放API调用失败!"); |
| | | msg.setData("设备回放API调用失败!"); |
| | | resultHolder.invokeResult(msg); |
| | | } |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) { |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setKey(DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId); |
| | | msg.setId(uuid); |
| | | StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId, uuid); |
| | | if (streamInfo != null) { |
| | | redisCatchStorage.startDownload(streamInfo); |
| | | msg.setData(JSON.toJSONString(streamInfo)); |
| | | resultHolder.invokeResult(msg); |
| | | } else { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) { |
| | | String streamId = resonse.getString("stream"); |
| | | JSONArray tracks = resonse.getJSONArray("tracks"); |
| | |
| | | * @param streamId |
| | | */ |
| | | void removePushStream(MediaServerItem mediaServerItem, String app, String streamId); |
| | | |
| | | /** |
| | | * 开始下载录像时存入 |
| | | * @param streamInfo |
| | | */ |
| | | boolean startDownload(StreamInfo streamInfo); |
| | | |
| | | StreamInfo queryDownloadByStreamId(String streamId); |
| | | } |
| | |
| | | streamInfo.getChannelId())); |
| | | } |
| | | @Override |
| | | public StreamInfo queryPlayByStreamId(String steamId) { |
| | | List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, steamId)); |
| | | public StreamInfo queryPlayByStreamId(String streamId) { |
| | | List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, streamId)); |
| | | if (playLeys == null || playLeys.size() == 0) return null; |
| | | return (StreamInfo)redis.get(playLeys.get(0).toString()); |
| | | } |
| | | |
| | | @Override |
| | | public StreamInfo queryPlaybackByStreamId(String steamId) { |
| | | List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, steamId)); |
| | | public StreamInfo queryPlaybackByStreamId(String streamId) { |
| | | List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, streamId)); |
| | | if (playLeys == null || playLeys.size() == 0) return null; |
| | | return (StreamInfo)redis.get(playLeys.get(0).toString()); |
| | | } |
| | |
| | | |
| | | @Override |
| | | public boolean startPlayback(StreamInfo stream) { |
| | | return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getChannelId()), |
| | | stream); |
| | | return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getStreamId(), |
| | | stream.getDeviceID(), stream.getChannelId()), stream); |
| | | } |
| | | |
| | | @Override |
| | | public boolean startDownload(StreamInfo streamInfo) { |
| | | return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, streamInfo.getStreamId(), |
| | | streamInfo.getDeviceID(), streamInfo.getChannelId()), streamInfo); |
| | | } |
| | | |
| | | @Override |
| | | public boolean stopPlayback(StreamInfo streamInfo) { |
| | |
| | | String key = VideoManagerConstants.WVP_SERVER_STREAM_PUSH_PREFIX + app + "_" + streamId + "_" + mediaServerItem.getId(); |
| | | redis.del(key); |
| | | } |
| | | |
| | | @Override |
| | | public StreamInfo queryDownloadByStreamId(String streamId) { |
| | | List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.DOWNLOAD_PREFIX, streamId)); |
| | | if (playLeys == null || playLeys.size() == 0) return null; |
| | | return (StreamInfo)redis.get(playLeys.get(0).toString()); |
| | | } |
| | | } |
| | |
| | | if (logger.isDebugEnabled()) { |
| | | logger.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed)); |
| | | } |
| | | String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; |
| | | String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId; |
| | | String uuid = UUID.randomUUID().toString(); |
| | | DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(30000L); |
| | | // 超时处理 |
| | |
| | | |
| | | cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (MediaServerItem mediaServerItem, JSONObject response) -> { |
| | | logger.info("收到订阅消息: " + response.toJSONString()); |
| | | playService.onPublishHandlerForPlayBack(mediaServerItem, response, deviceId, channelId, uuid.toString()); |
| | | playService.onPublishHandlerForDownload(mediaServerItem, response, deviceId, channelId, uuid.toString()); |
| | | }, event -> { |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setId(uuid); |
| | |
| | | logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); |
| | | } |
| | | String uuid = UUID.randomUUID().toString(); |
| | | String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; |
| | | String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId; |
| | | DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(30000L); |
| | | Device device = storager.queryVideoDevice(deviceId); |
| | | if (device == null) { |
| | |
| | | // 指定超时时间 1分钟30秒 |
| | | DeferredResult<ResponseEntity<RecordInfo>> result = new DeferredResult<>(90*1000L); |
| | | String uuid = UUID.randomUUID().toString(); |
| | | String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + channelId; |
| | | int sn = (int)((Math.random()*9+1)*100000); |
| | | String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn; |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setId(uuid); |
| | | msg.setKey(key); |
| | | cmder.recordInfoQuery(device, channelId, startTime, endTime, (eventResult -> { |
| | | cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, (eventResult -> { |
| | | msg.setData("查询录像失败, status: " + eventResult.statusCode + ", message: " + eventResult.msg ); |
| | | resultHolder.invokeResult(msg); |
| | | })); |