Merge branch '648540858:wvp-28181-2.0' into wvp-28181-2.0
| | |
| | | this.notUsed = notUsed; |
| | | } |
| | | |
| | | public boolean checkSsrc(String ssrcInResponse) { |
| | | return !isUsed.contains(ssrcInResponse); |
| | | } |
| | | } |
| | |
| | | * @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);
|
| | |
|
| | | /**
|
| | | * 请求回放视频流
|
| | |
| | | */
|
| | | @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;
|
| | |
| | | // 这里为例避免一个通道的点播只有一个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);
|
| | | });
|
| | |
|
| | |
|
| | |
| | | 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()) |
| | |
| | | // 由于海康会错误的发送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("/")) {
|
| | |
| | | |
| | | 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); |
| | | |
| | |
| | | |
| | | @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; |
| | | } |
| | |
| | | return null; |
| | | }else { |
| | | String ssrc = null; |
| | | if (presetSsrc != null) { |
| | | ssrc = presetSsrc; |
| | | }else { |
| | | if (isPlayback) { |
| | | ssrc = ssrcConfig.getPlayBackSsrc(); |
| | | }else { |
| | | ssrc = ssrcConfig.getPlaySsrc(); |
| | | } |
| | | } |
| | | |
| | | if (streamId == null) { |
| | | streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); |
| | |
| | | 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.*; |
| | |
| | | } |
| | | } |
| | | }, userSetting.getPlayTimeout()); |
| | | |
| | | final String ssrc = ssrcInfo.getSsrc(); |
| | | cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { |
| | | logger.info("收到订阅消息: " + response.toJSONString()); |
| | | timer.cancel(); |
| | |
| | | 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); |
| | | }); |
| | |
| | | <el-button size="mini" icon="el-icon-s-open" type="primary" v-if="scope.row.subCount > 0 || scope.row.parental === 1" |
| | | @click="changeSubchannel(scope.row)">查看 |
| | | </el-button> |
| | | <el-button size="mini" icon="el-icon-video-camera" type="primary" @click="queryRecords(scope.row)">设备录象 |
| | | <el-button size="mini" icon="el-icon-video-camera" type="primary" @click="queryRecords(scope.row)">设备录像 |
| | | </el-button> |
| | | <!-- <el-button size="mini" @click="sendDevicePush(scope.row)">录像查询</el-button> --> |
| | | </el-button-group> |
| | |
| | | > |
| | | <div id="shared" style="margin-top: 1rem;margin-right: 100px;"> |
| | | <el-form ref="form" :rules="rules" :model="form" label-width="140px" > |
| | | <!-- <el-form-item >--> |
| | | <!-- 建议的类型:--> |
| | | <!-- <br/>--> |
| | | <!--   行政区划(可选2位/4位/6位/8位/10位数字,例如:130432,表示河北省邯郸市广平县)--> |
| | | <!-- <br/>--> |
| | | <!--   业务分组(第11、12、13位215,例如:34020000002150000001)--> |
| | | <!-- <br/>--> |
| | | <!--   虚拟组织(第11、12、13位216,例如:34020000002160000001)--> |
| | | <!-- </el-form-item>--> |
| | | <el-form-item label="节点编号" prop="id" > |
| | | <el-tooltip class="item" effect="dark" content="" placement="top-start"> |
| | | <div slot="content"> |
| | | 建议的类型: |
| | | <br/> |
| | |   行政区划(可选2位/4位/6位/8位/10位数字,例如:130432,表示河北省邯郸市广平县) |
| | | <br/> |
| | |   业务分组(第11、12、13位215,例如:34020000002150000001) |
| | | <br/> |
| | |   虚拟组织(第11、12、13位216,例如:34020000002160000001) |
| | | </div> |
| | | <el-input v-model="form.id" :disabled="isEdit"></el-input> |
| | | </el-tooltip> |
| | | <el-input v-model="form.id" :disabled="isEdit" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="节点名称" prop="name"> |
| | | <el-input v-model="form.name" clearable></el-input> |
| | | </el-form-item> |
| | | |
| | | |
| | | <el-form-item> |
| | | <div style="float: right;"> |
| | |
| | | }, |
| | | 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; |
| | |
| | | }); |
| | | }, |
| | | 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) |
| | | }, |
| | | }, |
| | | }; |