diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java index ac54c2d9..2812c7df 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java @@ -136,4 +136,7 @@ public class SsrcConfig { this.notUsed = notUsed; } + public boolean checkSsrc(String ssrcInResponse) { + return !isUsed.contains(ssrcInResponse); + } } 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 a8fae0fb..f4bcbb64 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 @@ -93,8 +93,8 @@ public interface ISIPCommander { * @param device 视频设备 * @param channelId 预览通道 */ - void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent); - + void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent); + /** * 请求回放视频流 * 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 3fcf2fb2..a99ef4db 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 @@ -343,7 +343,7 @@ public class SIPCommander implements ISIPCommander { */ @Override public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, - ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) { + ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) { String streamId = ssrcInfo.getStream(); try { if (device == null) return; @@ -436,6 +436,7 @@ public class SIPCommander implements ISIPCommander { // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play); streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog); + okEvent.response(e); }); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java index da1088a2..42fcdeb0 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java @@ -202,6 +202,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme String platformId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); String deviceID = XmlUtil.getText(rootElement, "DeviceID"); ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); + if (platform == null)return; SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId); if (evt.getServerTransaction() == null) { ServerTransaction serverTransaction = platform.getTransport().equals("TCP") ? tcpSipProvider.getNewServerTransaction(evt.getRequest()) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java index 7a46ee7d..2caab0f8 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java @@ -222,7 +222,24 @@ public class XmlUtil { // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental")) == 1?1:0); } - deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID")); + /** + * 行政区划展示设备树与业务分组展示设备树是两种不同的模式 + * 行政区划展示设备树 各个目录之间主要靠deviceId做关联,摄像头通过CivilCode指定其属于那个行政区划;都是不超过十位的编号; 结构如下: + * 河北省 + * --> 石家庄市 + * --> 摄像头 + * --> 正定县 + * --> 摄像头 + * --> 摄像头 + * + * 业务分组展示设备树是顶级是业务分组,其下的虚拟组织靠BusinessGroupID指定其所属的业务分组;摄像头通过ParentId来指定其所属于的虚拟组织: + * 业务分组 + * --> 虚拟组织 + * --> 摄像头 + * --> 虚拟组织 + * --> 摄像头 + * --> 摄像头 + */ String parentId = XmlUtil.getText(itemDevice, "ParentID"); if (parentId != null) { if (parentId.contains("/")) { diff --git a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java index 2a99754f..4614ee7d 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java @@ -46,7 +46,7 @@ public interface IMediaServerService { SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck); - SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback); + SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback); void closeRTPServer(String deviceId, String channelId, String ssrc); diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java index e7b9e513..e311890c 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java @@ -118,11 +118,11 @@ public class MediaServerServiceImpl implements IMediaServerService { @Override public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck) { - return openRTPServer(mediaServerItem, streamId, ssrcCheck,false); + return openRTPServer(mediaServerItem, streamId, null, ssrcCheck,false); } @Override - public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback) { + public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck, boolean isPlayback) { if (mediaServerItem == null || mediaServerItem.getId() == null) { return null; } @@ -135,10 +135,14 @@ public class MediaServerServiceImpl implements IMediaServerService { return null; }else { String ssrc = null; - if (isPlayback) { - ssrc = ssrcConfig.getPlayBackSsrc(); + if (presetSsrc != null) { + ssrc = presetSsrc; }else { - ssrc = ssrcConfig.getPlaySsrc(); + if (isPlayback) { + ssrc = ssrcConfig.getPlayBackSsrc(); + }else { + ssrc = ssrcConfig.getPlaySsrc(); + } } if (streamId == null) { diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index 518b9d41..00daf107 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -39,6 +39,7 @@ import org.springframework.stereotype.Service; import org.springframework.util.ResourceUtils; import org.springframework.web.context.request.async.DeferredResult; +import javax.sip.ResponseEvent; import java.io.FileNotFoundException; import java.math.BigDecimal; import java.util.*; @@ -256,18 +257,46 @@ public class PlayServiceImpl implements IPlayService { } } }, userSetting.getPlayTimeout()); - + final String ssrc = ssrcInfo.getSsrc(); cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { logger.info("收到订阅消息: " + response.toJSONString()); timer.cancel(); // hook响应 onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId, uuid); hookEvent.response(mediaServerItemInuse, response); + }, (event) -> { + ResponseEvent responseEvent = (ResponseEvent)event.event; + String contentString = new String(responseEvent.getResponse().getRawContent()); + // 获取ssrc + int ssrcIndex = contentString.indexOf("y="); + // 检查是否有y字段 + if (ssrcIndex >= 0) { + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容 + String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); + if (!ssrc.equals(ssrcInResponse) && device.isSsrcCheck()) { // 查询到ssrc不一致且开启了ssrc校验则需要针对处理 + // 查询 ssrcInResponse 是否可用 + if (mediaServerItem.isRtpEnable() && !mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) { + // ssrc 不可用 + // 释放ssrc + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); + event.msg = "下级自定义了ssrc,但是此ssrc不可用"; + event.statusCode = 400; + errorEvent.response(event); + return; + } + // 关闭rtp server + mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); + // 重新开启ssrc server + mediaServerService.openRTPServer(mediaServerItem, finalSsrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false); + } + } }, (event) -> { timer.cancel(); mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); // 释放ssrc mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); errorEvent.response(event); }); diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue index 8d065426..7e0637c4 100644 --- a/web_src/src/components/channelList.vue +++ b/web_src/src/components/channelList.vue @@ -93,7 +93,7 @@ 查看 - 设备录象 + 设备录像 diff --git a/web_src/src/components/dialog/catalogEdit.vue b/web_src/src/components/dialog/catalogEdit.vue index 93d8f8dd..13cabfb5 100644 --- a/web_src/src/components/dialog/catalogEdit.vue +++ b/web_src/src/components/dialog/catalogEdit.vue @@ -12,25 +12,22 @@ >
+ + + + + + + + + - -
- 建议的类型: -
-   行政区划(可选2位/4位/6位/8位/10位数字,例如:130432,表示河北省邯郸市广平县) -
-   业务分组(第11、12、13位215,例如:34020000002150000001) -
-   虚拟组织(第11、12、13位216,例如:34020000002160000001) -
- -
+
-
确认 @@ -65,13 +62,14 @@ export default { }, rules: { name: [{ required: true, message: "请输入名称", trigger: "blur" }], - id: [{ required: true, message: "请输入id", trigger: "blur" }] + id: [{ required: true, message: "请输入ID", trigger: "blur" }] }, }; }, methods: { openDialog: function (isEdit, id, name, parentId, callback) { console.log("parentId: " + parentId) + console.log(this.form) this.isEdit = isEdit; this.form.id = id; this.form.name = name; @@ -105,8 +103,14 @@ export default { }); }, close: function () { + this.isEdit = false; + this.form.id = null; + this.form.name = null; + this.form.platformId = null; + this.form.parentId = null; + this.callback = null; this.showDialog = false; - this.$refs.form.resetFields(); + console.log(this.form) }, }, };