mk1990
2022-05-05 05a324a07a1848b020a06d671680907f8b92207d
Merge branch '648540858:wvp-28181-2.0' into wvp-28181-2.0
10个文件已修改
105 ■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/channelList.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/catalogEdit.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java
@@ -136,4 +136,7 @@
        this.notUsed = notUsed;
    }
    public boolean checkSsrc(String ssrcInResponse) {
        return !isUsed.contains(ssrcInResponse);
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -93,7 +93,7 @@
     * @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);
    
    /**
     * 请求回放视频流
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -343,7 +343,7 @@
      */
    @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 @@
                // 这里为例避免一个通道的点播只有一个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);
            });
            
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
@@ -202,6 +202,7 @@
        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())
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
@@ -222,7 +222,24 @@
            // 由于海康会错误的发送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("/")) {
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
@@ -46,7 +46,7 @@
    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);
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -118,11 +118,11 @@
    @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,11 +135,15 @@
            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();
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -39,6 +39,7 @@
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,7 +257,7 @@
                }
            }
        }, userSetting.getPlayTimeout());
        final String ssrc = ssrcInfo.getSsrc();
        cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
            logger.info("收到订阅消息: " + response.toJSONString());
            timer.cancel();
@@ -264,10 +265,38 @@
            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);
        });
web_src/src/components/channelList.vue
@@ -93,7 +93,7 @@
          <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>
web_src/src/components/dialog/catalogEdit.vue
@@ -12,24 +12,21 @@
    >
      <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/>-->
<!--            &emsp;&emsp;行政区划(可选2位/4位/6位/8位/10位数字,例如:130432,表示河北省邯郸市广平县)-->
<!--            <br/>-->
<!--            &emsp;&emsp;业务分组(第11、12、13位215,例如:34020000002150000001)-->
<!--            <br/>-->
<!--            &emsp;&emsp;虚拟组织(第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/>
                &emsp;&emsp;行政区划(可选2位/4位/6位/8位/10位数字,例如:130432,表示河北省邯郸市广平县)
                <br/>
                &emsp;&emsp;业务分组(第11、12、13位215,例如:34020000002150000001)
                <br/>
                &emsp;&emsp;虚拟组织(第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;">
@@ -65,13 +62,14 @@
      },
      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 @@
        });
    },
    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)
    },
  },
};