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 f4774393..96a987c9 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java @@ -87,6 +87,9 @@ public class StreamInfo implements Serializable, Cloneable{ @Schema(description = "产生源类型,包括 unknown = 0,rtmp_push=1,rtsp_push=2,rtp_push=3,pull=4,ffmpeg_pull=5,mp4_vod=6,device_chn=7") private int originType; + @Schema(description = "转码后的视频流") + private StreamInfo transcodeStream; + public void setFlv(StreamURL flv) { this.flv = flv; } @@ -533,6 +536,14 @@ public class StreamInfo implements Serializable, Cloneable{ this.transactionInfo = transactionInfo; } + public StreamInfo getTranscodeStream() { + return transcodeStream; + } + + public void setTranscodeStream(StreamInfo transcodeStream) { + this.transcodeStream = transcodeStream; + } + @Override public StreamInfo clone() { StreamInfo instance = null; diff --git a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java index 007c72a3..18114c5a 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java @@ -21,7 +21,7 @@ public class UserSetting { private Boolean seniorSdp = Boolean.FALSE; - private Integer playTimeout = 18000; + private Integer playTimeout = 10000; private int platformPlayTimeout = 20000; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogChannelEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogChannelEvent.java new file mode 100644 index 00000000..cf7c9cbd --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogChannelEvent.java @@ -0,0 +1,38 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; +import org.dom4j.Element; + +import java.lang.reflect.InvocationTargetException; + +@Data +@Slf4j +@EqualsAndHashCode(callSuper = true) +public class CatalogChannelEvent extends DeviceChannel{ + + private String event; + + private DeviceChannel channel; + + public static CatalogChannelEvent decode(Element element) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + Element eventElement = element.element("Event"); + CatalogChannelEvent catalogChannelEvent = new CatalogChannelEvent(); + if (eventElement != null) { + catalogChannelEvent.setEvent(eventElement.getText()); + }else { + catalogChannelEvent.setEvent(CatalogEvent.ADD); + } + DeviceChannel deviceChannel; + if (CatalogEvent.ADD.equalsIgnoreCase(catalogChannelEvent.getEvent()) || + CatalogEvent.UPDATE.equalsIgnoreCase(catalogChannelEvent.getEvent()) ){ + deviceChannel = DeviceChannel.decode(element); + }else { + deviceChannel = DeviceChannel.decodeWithOnlyDeviceId(element); + } + catalogChannelEvent.setChannel(deviceChannel); + return catalogChannelEvent; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogEvent.java deleted file mode 100644 index a3fcdee8..00000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogEvent.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.bean; - -import com.genersoft.iot.vmp.gb28181.utils.MessageElement; - -public class CatalogEvent extends DeviceChannel{ - - @MessageElement("Event") - private String event; -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java index a9842123..816917d4 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java @@ -7,6 +7,9 @@ import lombok.Data; @Schema(description = "国标通道") public class CommonGBChannel { + @Schema(description = "国标-数据库自增ID") + private int gbId; + @Schema(description = "国标-编码") private String gbDeviceId; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java index 5ddf1c46..09f28785 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java @@ -1,257 +1,170 @@ package com.genersoft.iot.vmp.gb28181.bean; import com.genersoft.iot.vmp.gb28181.utils.MessageElement; +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; +import org.dom4j.Element; + +import java.lang.reflect.InvocationTargetException; @Data +@Slf4j @Schema(description = "通道信息") @EqualsAndHashCode(callSuper = true) public class DeviceChannel extends CommonGBChannel { + @Schema(description = "数据库自增ID") + private int id; + @MessageElement("DeviceID") @Schema(description = "编码") private String deviceId; - @MessageElement("DeviceID") + @MessageElement("Name") @Schema(description = "名称") private String name; - @MessageElement("DeviceID") + @MessageElement("Manufacturer") @Schema(description = "设备厂商") private String manufacturer; - @MessageElement("DeviceID") + @MessageElement("Model") @Schema(description = "设备型号") private String model; // 2016 - @MessageElement("DeviceID") + @MessageElement("Owner") @Schema(description = "设备归属") private String owner; - @MessageElement("DeviceID") + @MessageElement("CivilCode") @Schema(description = "行政区域") private String civilCode; - @MessageElement("DeviceID") + @MessageElement("Block") @Schema(description = "警区") private String block; - @MessageElement("DeviceID") + @MessageElement("Address") @Schema(description = "安装地址") private String address; - @MessageElement("DeviceID") - @Schema(description = "是否有子设备") - private Boolean parental; + @MessageElement("Parental") + @Schema(description = "是否有子设备(必选)1有,0没有") + private Integer parental; - @MessageElement("DeviceID") + @MessageElement("ParentID") @Schema(description = "父节点ID") private String parentId; // 2016 - @MessageElement("DeviceID") + @MessageElement("SafetyWay") @Schema(description = "信令安全模式") private Integer safetyWay; - @MessageElement("DeviceID") + @MessageElement("RegisterWay") @Schema(description = "注册方式") private Integer registerWay; // 2016 - @MessageElement("DeviceID") + @MessageElement("CertNum") @Schema(description = "证书序列号") - private Integer certNum; + private String certNum; // 2016 - @MessageElement("DeviceID") - @Schema(description = "证书有效标识") + @MessageElement("Certifiable") + @Schema(description = "证书有效标识, 缺省为0;证书有效标识:0:无效 1:有效") private Integer certifiable; // 2016 - @MessageElement("DeviceID") + @MessageElement("ErrCode") @Schema(description = "无效原因码(有证书且证书无效的设备必选)") private Integer errCode; // 2016 - @MessageElement("DeviceID") + @MessageElement("EndTime") @Schema(description = "证书终止有效期(有证书且证书无效的设备必选)") - private Integer endTime; + private String endTime; - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机安全能力等级代码") - private String securityLevelCode; - - @MessageElement("DeviceID") + @MessageElement("Secrecy") @Schema(description = "保密属性(必选)缺省为0;0-不涉密,1-涉密") private Integer secrecy; - @MessageElement("DeviceID") + @MessageElement("IPAddress") @Schema(description = "设备/系统IPv4/IPv6地址") private String ipAddress; - @MessageElement("DeviceID") + @MessageElement("Port") @Schema(description = "设备/系统端口") private Integer port; - @MessageElement("DeviceID") + @MessageElement("Password") @Schema(description = "设备口令") private String password; - @MessageElement("DeviceID") + @MessageElement("Status") @Schema(description = "设备状态") - private Boolean status; + private String status; - @MessageElement("DeviceID") + @MessageElement("Longitude") @Schema(description = "经度 WGS-84坐标系") private Double longitude; - @MessageElement("DeviceID") + @MessageElement("Latitude") @Schema(description = ",纬度 WGS-84坐标系") private Double latitude; - @MessageElement("DeviceID") - @Schema(description = "虚拟组织所属的业务分组ID") - private String businessGroupId; - - @MessageElement("DeviceID") + @MessageElement("Info.PTZType") @Schema(description = "摄像机结构类型,标识摄像机类型: 1-球机; 2-半球; 3-固定枪机; 4-遥控枪机;5-遥控半球;6-多目设备的全景/拼接通道;7-多目设备的分割通道") private Integer ptzType; - @MessageElement("DeviceID") - @Schema(description = "摄像机光电成像类型。1-可见光成像;2-热成像;3-雷达成像;4-X光成像;5-深度光场成像;9-其他。可多值,") - private String photoelectricImagingTyp; + @MessageElement("Info.PositionType") + @Schema(description = "摄像机位置类型扩展。1-省际检查站、2-党政机关、3-车站码头、4-中心广场、5-体育场馆、" + + "6-商业中心、7-宗教场所、8-校园周边、9-治安复杂区域、10-交通干线") + private Integer positionType; - @MessageElement("DeviceID") - @Schema(description = "摄像机采集部位类型") - private String capturePositionType; - - @MessageElement("DeviceID") + @MessageElement("Info.RoomType") @Schema(description = "摄像机安装位置室外、室内属性。1-室外、2-室内。") private Integer roomType; - // 2016 - @MessageElement("DeviceID") - @Schema(description = "用途属性") + @MessageElement("Info.UseType") + @Schema(description = "用途属性, 1-治安、2-交通、3-重点。") private Integer useType; - @MessageElement("DeviceID") + @MessageElement("Info.SupplyLightType") @Schema(description = "摄像机补光属性。1-无补光;2-红外补光;3-白光补光;4-激光补光;9-其他") private Integer supplyLightType; - @MessageElement("DeviceID") + @MessageElement("Info.DirectionType") @Schema(description = "摄像机监视方位(光轴方向)属性。1-东(西向东)、2-西(东向西)、3-南(北向南)、4-北(南向北)、" + "5-东南(西北到东南)、6-东北(西南到东北)、7-西南(东北到西南)、8-西北(东南到西北)") private Integer directionType; - @MessageElement("DeviceID") + @MessageElement("Info.Resolution") @Schema(description = "摄像机支持的分辨率,可多值") private String resolution; - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机支持的码流编号列表,用于实时点播时指定码流编号(可选)") - private String streamNumberList; + @MessageElement("Info.BusinessGroupID") + @Schema(description = "虚拟组织所属的业务分组ID") + private String businessGroupId; - @MessageElement("DeviceID") + @MessageElement("Info.DownloadSpeed") @Schema(description = "下载倍速(可选),可多值") private String downloadSpeed; - @MessageElement("DeviceID") + @MessageElement("Info.SVCSpaceSupportMode") @Schema(description = "空域编码能力,取值0-不支持;1-1级增强(1个增强层);2-2级增强(2个增强层);3-3级增强(3个增强层)") private Integer svcSpaceSupportMod; - @MessageElement("DeviceID") + @MessageElement("Info.SVCTimeSupportMode") @Schema(description = "时域编码能力,取值0-不支持;1-1级增强;2-2级增强;3-3级增强(可选)") private Integer svcTimeSupportMode; - // 2022 - @MessageElement("DeviceID") - @Schema(description = " SSVC增强层与基本层比例能力 ") - private String ssvcRatioSupportList; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "移动采集设备类型(仅移动采集设备适用,必选);1-移动机器人载摄像机;2-执法记录仪;3-移动单兵设备;" + - "4-车载视频记录设备;5-无人机载摄像机;9-其他") - private Integer mobileDeviceType; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机水平视场角(可选),取值范围大于0度小于等于360度") - private Double horizontalFieldAngle; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机竖直视场角(可选),取值范围大于0度小于等于360度 ") - private Double verticalFieldAngle; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机可视距离(可选),单位:米") - private Double maxViewDistance; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "基层组织编码(必选,非基层建设时为“000000”)") - private String grassrootsCode; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "监控点位类型(当为摄像机时必选),1-一类视频监控点;2-二类视频监控点;3-三类视频监控点;9-其他点位。") - private Integer poType; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "点位俗称") - private String poCommonName; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "设备MAC地址(可选),用“XX-XX-XX-XX-XX-XX”格式表达") - private String mac; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机卡口功能类型,01-人脸卡口;02-人员卡口;03-机动车卡口;04-非机动车卡口;05-物品卡口;99-其他") - private String functionType; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机视频编码格式") - private String encodeType; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机安装使用时间") - private String installTime; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机所属管理单位名称") - private String managementUnit; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机所属管理单位联系人的联系方式(电话号码,可多值,用英文半角“/”分割)") - private String contactInfo; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "录像保存天数(可选)") - private Integer recordSaveDays; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "国民经济行业分类代码(可选)") - private String industrialClassification; - - @Schema(description = "云台类型描述字符串") private String ptzTypeText; @@ -306,4 +219,15 @@ public class DeviceChannel extends CommonGBChannel { break; } } + + public static DeviceChannel decode(Element element) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + return XmlUtil.elementDecode(element, DeviceChannel.class); + } + + public static DeviceChannel decodeWithOnlyDeviceId(Element element) { + Element deviceElement = element.element("DeviceID"); + DeviceChannel deviceChannel = new DeviceChannel(); + deviceChannel.setDeviceId(deviceElement.getText()); + return deviceChannel; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java index 18ad2b01..9c65b873 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java @@ -5,8 +5,7 @@ import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; import com.genersoft.iot.vmp.service.IGbStreamService; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @@ -23,11 +22,10 @@ import java.util.Map; /** * catalog事件 */ +@Slf4j @Component public class CatalogEventLister implements ApplicationListener { - private final static Logger logger = LoggerFactory.getLogger(CatalogEventLister.class); - @Autowired private IVideoManagerStorage storager; @@ -66,9 +64,9 @@ public class CatalogEventLister implements ApplicationListener { if (event.getDeviceChannels() != null) { if (platforms.size() > 0) { for (DeviceChannel deviceChannel : event.getDeviceChannels()) { - List parentPlatformsForGB = storager.queryPlatFormListForGBWithGBId(deviceChannel.getChannelId(), platforms); - parentPlatformMap.put(deviceChannel.getChannelId(), parentPlatformsForGB); - channelMap.put(deviceChannel.getChannelId(), deviceChannel); + List parentPlatformsForGB = storager.queryPlatFormListForGBWithGBId(deviceChannel.getDeviceId(), platforms); + parentPlatformMap.put(deviceChannel.getDeviceId(), parentPlatformsForGB); + channelMap.put(deviceChannel.getDeviceId(), deviceChannel); } } }else if (event.getGbStreams() != null) { @@ -106,12 +104,12 @@ public class CatalogEventLister implements ApplicationListener { } } if (deviceChannelList.size() > 0) { - logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); + log.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); try { sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), parentPlatform, deviceChannelList, subscribe, null); } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | IllegalAccessException e) { - logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + log.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); } } }else if (parentPlatformMap.keySet().size() > 0) { @@ -123,16 +121,16 @@ public class CatalogEventLister implements ApplicationListener { if (subscribeInfo == null) { continue; } - logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId); + log.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId); List deviceChannelList = new ArrayList<>(); DeviceChannel deviceChannel = new DeviceChannel(); - deviceChannel.setChannelId(gbId); + deviceChannel.setDeviceId(gbId); deviceChannelList.add(deviceChannel); try { sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), platform, deviceChannelList, subscribeInfo, null); } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | IllegalAccessException e) { - logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + log.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); } } } @@ -157,12 +155,12 @@ public class CatalogEventLister implements ApplicationListener { } } if (!deviceChannelList.isEmpty()) { - logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); + log.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); try { sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), parentPlatform, deviceChannelList, subscribe, null); } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | IllegalAccessException e) { - logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + log.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); } } }else if (!parentPlatformMap.keySet().isEmpty()) { @@ -174,7 +172,7 @@ public class CatalogEventLister implements ApplicationListener { if (subscribeInfo == null) { continue; } - logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId); + log.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId); List deviceChannelList = new ArrayList<>(); DeviceChannel deviceChannel = channelMap.get(gbId); deviceChannelList.add(deviceChannel); @@ -187,7 +185,7 @@ public class CatalogEventLister implements ApplicationListener { sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), platform, deviceChannelList, subscribeInfo, null); } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | IllegalAccessException e) { - logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + log.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java new file mode 100644 index 00000000..4858bc5a --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java @@ -0,0 +1,25 @@ +package com.genersoft.iot.vmp.gb28181.service; + +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; + +import java.util.List; + +public interface IGbChannelService { + + CommonGBChannel queryByDeviceId(String gbDeviceId); + + int add(CommonGBChannel commonGBChannel); + + int delete(int gbId); + + int update(CommonGBChannel commonGBChannel); + + int offline(CommonGBChannel commonGBChannel); + + int online(CommonGBChannel commonGBChannel); + + void closeSend(CommonGBChannel commonGBChannel); + + void batchAdd(List commonGBChannels); + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java new file mode 100644 index 00000000..adf5251c --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java @@ -0,0 +1,10 @@ +package com.genersoft.iot.vmp.gb28181.service.impl; + +import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class GbChannelServiceImpl implements IGbChannelService { +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index fe827f5a..4763f0fe 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -27,6 +27,9 @@ import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxy; import com.genersoft.iot.vmp.media.zlm.dto.StreamPush; +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; +import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.service.IPlayService; import com.genersoft.iot.vmp.service.IStreamProxyService; import com.genersoft.iot.vmp.service.IStreamPushService; @@ -593,12 +596,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements sendRtpItem.setPlayType(InviteStreamType.PUSH); if (streamPushItem != null) { // 从redis查询是否正在接收这个推流 - StreamPush pushListItem = redisCatchStorage.getPushListItem(gbStream.getApp(), gbStream.getStream()); + OnStreamChangedHookParam pushListItem = redisCatchStorage.getPushListItem(gbStream.getApp(), gbStream.getStream()); if (pushListItem != null) { - sendRtpItem.setServerId(pushListItem.getServerId()); + sendRtpItem.setServerId(pushListItem.getSeverId()); sendRtpItem.setMediaServerId(pushListItem.getMediaServerId()); - pushListItem.setSelf(userSetting.getServerId().equals(pushListItem.getServerId())); redisCatchStorage.updateSendRTPSever(sendRtpItem); // 开始推流 sendPushStream(sendRtpItem, mediaServerItem, platform, request); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java index c832161a..37587b2d 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.gb28181.bean.CatalogChannelEvent; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.HandlerCatchData; @@ -10,14 +11,12 @@ import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; -import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import com.genersoft.iot.vmp.service.IDeviceChannelService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.utils.DateUtil; +import lombok.extern.slf4j.Slf4j; import org.dom4j.DocumentException; import org.dom4j.Element; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -25,6 +24,8 @@ import org.springframework.transaction.annotation.Transactional; import javax.sip.RequestEvent; import javax.sip.header.FromHeader; +import java.lang.reflect.InvocationTargetException; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -36,12 +37,10 @@ import java.util.concurrent.CopyOnWriteArrayList; /** * SIP命令类型: NOTIFY请求中的目录请求处理 */ +@Slf4j @Component public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent { - - private final static Logger logger = LoggerFactory.getLogger(NotifyRequestForCatalogProcessor.class); - private final List updateChannelOnlineList = new CopyOnWriteArrayList<>(); private final List updateChannelOfflineList = new CopyOnWriteArrayList<>(); private final Map updateChannelMap = new ConcurrentHashMap<>(); @@ -72,7 +71,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent @Transactional public void process(RequestEvent evt) { if (taskQueue.size() >= userSetting.getMaxNotifyCountQueue()) { - logger.error("[notify-目录订阅] 待处理消息队列已满 {},返回486 BUSY_HERE,消息不做处理", userSetting.getMaxNotifyCountQueue()); + log.error("[notify-目录订阅] 待处理消息队列已满 {},返回486 BUSY_HERE,消息不做处理", userSetting.getMaxNotifyCountQueue()); return; } taskQueue.offer(new HandlerCatchData(evt, null, null)); @@ -95,12 +94,12 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent Device device = redisCatchStorage.getDevice(deviceId); if (device == null || !device.isOnLine()) { - logger.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId() : "")); + log.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId() : "")); return; } Element rootElement = getRootElement(evt, device.getCharset()); if (rootElement == null) { - logger.warn("[ 收到目录订阅 ] content cannot be null, {}", evt.getRequest()); + log.warn("[ 收到目录订阅 ] content cannot be null, {}", evt.getRequest()); return; } Element deviceListElement = rootElement.element("DeviceList"); @@ -113,132 +112,134 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent // 遍历DeviceList while (deviceListIterator.hasNext()) { Element itemDevice = deviceListIterator.next(); - Element eventElement = itemDevice.element("Event"); - String event; - if (eventElement == null) { - logger.warn("[收到目录订阅]:{}, 但是Event为空, 设为默认值 ADD", (device != null ? device.getDeviceId() : "")); - event = CatalogEvent.ADD; - } else { - event = eventElement.getText().toUpperCase(); - } - DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, event); - - - if (channel == null) { - logger.info("[收到目录订阅]:但是解析失败 {}", new String(evt.getRequest().getRawContent())); + CatalogChannelEvent catalogChannelEvent = null; + try { + catalogChannelEvent = CatalogChannelEvent.decode(itemDevice); + if (catalogChannelEvent.getChannel() == null) { + log.info("[解析CatalogChannelEvent]成功:但是解析通道信息失败, 原文如下: \n{}", new String(evt.getRequest().getRawContent())); + continue; + } + } catch (InvocationTargetException | NoSuchMethodException | InstantiationException | + IllegalAccessException e) { + log.error("[解析CatalogChannelEvent]失败,", e); + log.error("[解析CatalogChannelEvent]失败原文: \n{}", new String(evt.getRequest().getRawContent(), Charset.forName(device.getCharset()))); + continue; + } + if (catalogChannelEvent == null) { continue; } - if (channel.getParentId() != null && channel.getParentId().equals(sipConfig.getId())) { - channel.setParentId(null); - } - channel.setDeviceId(device.getDeviceId()); - logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getDeviceId()); - switch (event) { + + log.info("[收到目录订阅]:{}/{}-{}", device.getDeviceId(), + catalogChannelEvent.getChannel().getDeviceId(), catalogChannelEvent.getEvent()); + switch (catalogChannelEvent.getEvent()) { case CatalogEvent.ON: // 上线 - logger.info("[收到通道上线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); - updateChannelOnlineList.add(channel); + log.info("[收到通道上线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); + updateChannelOnlineList.add(catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), true); + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), true); } break; case CatalogEvent.OFF: // 离线 - logger.info("[收到通道离线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道离线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); if (userSetting.getRefuseChannelStatusChannelFormNotify()) { - logger.info("[收到通道离线通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道离线通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); } else { - updateChannelOfflineList.add(channel); + updateChannelOfflineList.add(catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), false); + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), false); } } break; case CatalogEvent.VLOST: // 视频丢失 - logger.info("[收到通道视频丢失通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道视频丢失通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); if (userSetting.getRefuseChannelStatusChannelFormNotify()) { - logger.info("[收到通道视频丢失通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道视频丢失通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); } else { - updateChannelOfflineList.add(channel); + updateChannelOfflineList.add(catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), false); + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), false); } } break; case CatalogEvent.DEFECT: // 故障 - logger.info("[收到通道视频故障通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道视频故障通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); if (userSetting.getRefuseChannelStatusChannelFormNotify()) { - logger.info("[收到通道视频故障通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道视频故障通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); } else { - updateChannelOfflineList.add(channel); + updateChannelOfflineList.add(catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), false); + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), false); } } break; case CatalogEvent.ADD: // 增加 - logger.info("[收到增加通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到增加通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); // 判断此通道是否存在 - DeviceChannel deviceChannel = deviceChannelService.getOne(deviceId, channel.getChannelId()); + DeviceChannel deviceChannel = deviceChannelService.getOne(deviceId, catalogChannelEvent.getChannel().getDeviceId()); if (deviceChannel != null) { - logger.info("[增加通道] 已存在,不发送通知只更新,设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[增加通道] 已存在,不发送通知只更新,设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); + DeviceChannel channel = catalogChannelEvent.getChannel(); channel.setId(deviceChannel.getId()); - channel.setHasAudio(null); - updateChannelMap.put(channel.getChannelId(), channel); + channel.setHasAudio(deviceChannel.getHasAudio()); + channel.setUpdateTime(DateUtil.getNow()); + updateChannelMap.put(catalogChannelEvent.getChannel().getDeviceId(), channel); } else { - addChannelMap.put(channel.getChannelId(), channel); + addChannelMap.put(catalogChannelEvent.getChannel().getDeviceId(), catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true); + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), true); } } break; case CatalogEvent.DEL: // 删除 - logger.info("[收到删除通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); - deleteChannelList.add(channel); + log.info("[收到删除通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); + deleteChannelList.add(catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), false); + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), false); } break; case CatalogEvent.UPDATE: // 更新 - logger.info("[收到更新通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到更新通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); // 判断此通道是否存在 - DeviceChannel deviceChannelForUpdate = deviceChannelService.getOne(deviceId, channel.getChannelId()); + DeviceChannel deviceChannelForUpdate = deviceChannelService.getOne(deviceId, catalogChannelEvent.getChannel().getDeviceId()); if (deviceChannelForUpdate != null) { + DeviceChannel channel = catalogChannelEvent.getChannel(); channel.setId(deviceChannelForUpdate.getId()); + channel.setHasAudio(deviceChannelForUpdate.getHasAudio()); channel.setUpdateTime(DateUtil.getNow()); - channel.setHasAudio(null); - updateChannelMap.put(channel.getChannelId(), channel); + updateChannelMap.put(catalogChannelEvent.getChannel().getDeviceId(), channel); } else { - addChannelMap.put(channel.getChannelId(), channel); + addChannelMap.put(catalogChannelEvent.getChannel().getDeviceId(), catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true); + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), true); } } break; default: - logger.warn("[ NotifyCatalog ] event not found : {}", event); + log.warn("[ NotifyCatalog ] event not found : {}", catalogChannelEvent.getEvent()); } // 转发变化信息 - eventPublisher.catalogEventPublish(null, channel, event); + eventPublisher.catalogEventPublish(null, catalogChannelEvent.getChannel(), catalogChannelEvent.getEvent()); } } } catch (DocumentException e) { - logger.error("未处理的异常 ", e); + log.error("未处理的异常 ", e); } } taskQueue.clear(); @@ -255,33 +256,33 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent try { executeSaveForAdd(); } catch (Exception e) { - logger.error("[存储收到的增加通道] 异常: ", e ); + log.error("[存储收到的增加通道] 异常: ", e ); } try { executeSaveForOnline(); } catch (Exception e) { - logger.error("[存储收到的通道上线] 异常: ", e ); + log.error("[存储收到的通道上线] 异常: ", e ); } try { executeSaveForOffline(); } catch (Exception e) { - logger.error("[存储收到的通道离线] 异常: ", e ); + log.error("[存储收到的通道离线] 异常: ", e ); } try { executeSaveForUpdate(); } catch (Exception e) { - logger.error("[存储收到的更新通道] 异常: ", e ); + log.error("[存储收到的更新通道] 异常: ", e ); } try { executeSaveForDelete(); } catch (Exception e) { - logger.error("[存储收到的删除通道] 异常: ", e ); + log.error("[存储收到的删除通道] 异常: ", e ); } } private void executeSaveForUpdate(){ if (!updateChannelMap.values().isEmpty()) { - logger.info("[存储收到的更新通道], 数量: {}", updateChannelMap.size()); + log.info("[存储收到的更新通道], 数量: {}", updateChannelMap.size()); ArrayList deviceChannels = new ArrayList<>(updateChannelMap.values()); deviceChannelService.batchUpdateChannel(deviceChannels); updateChannelMap.clear(); @@ -317,8 +318,8 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent } } - @Scheduled(fixedRate = 10000) //每1秒执行一次 - public void execute(){ - logger.info("[待处理Notify-目录订阅消息数量]: {}", taskQueue.size()); - } +// @Scheduled(fixedRate = 10000) //每1秒执行一次 +// public void execute(){ +// logger.info("[待处理Notify-目录订阅消息数量]: {}", taskQueue.size()); +// } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java index 52fc7a3f..9c414a85 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java @@ -188,8 +188,8 @@ public class NotifyRequestForMobilePositionProcessor extends SIPRequestProcessor } taskQueue.clear(); } - @Scheduled(fixedRate = 10000) - public void execute(){ - logger.info("[待处理Notify-移动位置订阅消息数量]: {}", taskQueue.size()); - } +// @Scheduled(fixedRate = 10000) +// public void execute(){ +// logger.debug("[待处理Notify-移动位置订阅消息数量]: {}", taskQueue.size()); +// } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java index c16d7f56..c2b0b2de 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java @@ -7,7 +7,6 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; -import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import gov.nist.javax.sip.message.SIPRequest; import org.dom4j.DocumentException; @@ -114,8 +113,9 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp if (channelDeviceElement == null) { continue; } - DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, null); - if (channel == null) { + DeviceChannel channel = DeviceChannel.decode(itemDevice); +// DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, null); + if (channel == null || channel.getDeviceId() == null) { logger.info("[收到目录订阅]:但是解析失败 {}", new String(evt.getRequest().getRawContent())); continue; } 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 cb874802..46e92480 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 @@ -2,13 +2,6 @@ package com.genersoft.iot.vmp.gb28181.utils; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; -import com.genersoft.iot.vmp.common.CivilCodePo; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; -import com.genersoft.iot.vmp.utils.CivilCodeUtil; -import com.genersoft.iot.vmp.utils.DateUtil; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.dom4j.Attribute; import org.dom4j.Document; @@ -240,388 +233,387 @@ public class XmlUtil { CivilCode, BusinessGroup,VirtualOrganization,Other } - public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event){ - loadElement(itemDevice, DeviceChannel.class) - DeviceChannel deviceChannel = new DeviceChannel(); - deviceChannel.setDeviceId(device.getDeviceId()); - Element channdelIdElement = itemDevice.element("DeviceID"); - if (channdelIdElement == null) { - logger.warn("解析Catalog消息时发现缺少 DeviceID"); - return null; - } - String channelId = channdelIdElement.getTextTrim(); - if (ObjectUtils.isEmpty(channelId)) { - logger.warn("解析Catalog消息时发现缺少 DeviceID"); - return null; - } - deviceChannel.setChannelId(channelId); - if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) { - // 除了ADD和update情况下需要识别全部内容, - return deviceChannel; - } - Element nameElement = itemDevice.element("Name"); - // 当通道名称为空时,设置通道名称为通道编码,避免级联时因通道名称为空导致上级接收通道失败 - if (nameElement != null && StringUtils.isNotBlank(nameElement.getText())) { - deviceChannel.setName(nameElement.getText()); - } else { - deviceChannel.setName(channelId); - } - if(channelId.length() <= 8) { - deviceChannel.setHasAudio(false); - CivilCodePo parentCode = CivilCodeUtil.INSTANCE.getParentCode(channelId); - if (parentCode != null) { - deviceChannel.setParentId(parentCode.getCode()); - deviceChannel.setCivilCode(parentCode.getCode()); - }else { - logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId); - } - deviceChannel.setStatus(true); - return deviceChannel; - }else { - if(channelId.length() != 20) { - logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId); - return null; - } - - int code = Integer.parseInt(channelId.substring(10, 13)); - if (code == 136 || code == 137 || code == 138) { - deviceChannel.setHasAudio(true); - }else { - deviceChannel.setHasAudio(false); - } - // 设备厂商 - String manufacturer = getText(itemDevice, "Manufacturer"); - // 设备型号 - String model = getText(itemDevice, "Model"); - // 设备归属 - String owner = getText(itemDevice, "Owner"); - // 行政区域 - String civilCode = getText(itemDevice, "CivilCode"); - // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织 - String businessGroupID = getText(itemDevice, "BusinessGroupID"); - // 父设备/区域/系统ID - String parentID = getText(itemDevice, "ParentID"); - if (parentID != null && parentID.equalsIgnoreCase("null")) { - parentID = null; - } - // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式 - String registerWay = getText(itemDevice, "RegisterWay"); - // 保密属性(必选)缺省为0;0:不涉密,1:涉密 - String secrecy = getText(itemDevice, "Secrecy"); - // 安装地址 - String address = getText(itemDevice, "Address"); - - switch (code){ - case 200: - // 系统目录 - if (!ObjectUtils.isEmpty(manufacturer)) { - deviceChannel.setManufacture(manufacturer); - } - if (!ObjectUtils.isEmpty(model)) { - deviceChannel.setModel(model); - } - if (!ObjectUtils.isEmpty(owner)) { - deviceChannel.setOwner(owner); - } - if (!ObjectUtils.isEmpty(civilCode)) { - deviceChannel.setCivilCode(civilCode); - deviceChannel.setParentId(civilCode); - }else { - if (!ObjectUtils.isEmpty(parentID)) { - deviceChannel.setParentId(parentID); - } - } - if (!ObjectUtils.isEmpty(address)) { - deviceChannel.setAddress(address); - } - deviceChannel.setStatus(true); - if (!ObjectUtils.isEmpty(registerWay)) { - try { - deviceChannel.setRegisterWay(Integer.parseInt(registerWay)); - }catch (NumberFormatException exception) { - logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); - } - } - if (!ObjectUtils.isEmpty(secrecy)) { - deviceChannel.setSecrecy(secrecy); - } - return deviceChannel; - case 215: - // 业务分组 - deviceChannel.setStatus(true); - if (!ObjectUtils.isEmpty(parentID)) { - if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) { - deviceChannel.setParentId(parentID); - } - }else { - logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId"); - if (!ObjectUtils.isEmpty(civilCode)) { - deviceChannel.setCivilCode(civilCode); - } - } - break; - case 216: - // 虚拟组织 - deviceChannel.setStatus(true); - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setBusinessGroupId(businessGroupID); - } - - if (!ObjectUtils.isEmpty(parentID)) { - if (parentID.contains("/")) { - String[] parentIdArray = parentID.split("/"); - parentID = parentIdArray[parentIdArray.length - 1]; - } - deviceChannel.setParentId(parentID); - }else { - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setParentId(businessGroupID); - } - } - break; - default: - // 设备目录 - if (!ObjectUtils.isEmpty(manufacturer)) { - deviceChannel.setManufacture(manufacturer); - } - if (!ObjectUtils.isEmpty(model)) { - deviceChannel.setModel(model); - } - if (!ObjectUtils.isEmpty(owner)) { - deviceChannel.setOwner(owner); - } - if (!ObjectUtils.isEmpty(civilCode) - && civilCode.length() <= 8 - && NumberUtils.isParsable(civilCode) - && civilCode.length()%2 == 0 - ) { - deviceChannel.setCivilCode(civilCode); - } - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setBusinessGroupId(businessGroupID); - } - - // 警区 - String block = getText(itemDevice, "Block"); - if (!ObjectUtils.isEmpty(block)) { - deviceChannel.setBlock(block); - } - if (!ObjectUtils.isEmpty(address)) { - deviceChannel.setAddress(address); - } - - if (!ObjectUtils.isEmpty(secrecy)) { - deviceChannel.setSecrecy(secrecy); - } - - // 当为设备时,是否有子设备(必选)1有,0没有 - String parental = getText(itemDevice, "Parental"); - if (!ObjectUtils.isEmpty(parental)) { - try { - // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 - if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) { - deviceChannel.setParental(0); - }else { - deviceChannel.setParental(1); - } - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental); - } - } - // 父设备/区域/系统ID - - if (!ObjectUtils.isEmpty(parentID) ) { - if (parentID.contains("/")) { - String[] parentIdArray = parentID.split("/"); - deviceChannel.setParentId(parentIdArray[parentIdArray.length - 1]); - }else { - if (parentID.length()%2 == 0) { - deviceChannel.setParentId(parentID); - }else { - logger.warn("[xml解析] 不规范的parentID:{}, 已舍弃", parentID); - } - } - }else { - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setParentId(businessGroupID); - }else { - if (!ObjectUtils.isEmpty(deviceChannel.getCivilCode())) { - deviceChannel.setParentId(deviceChannel.getCivilCode()); - } - } - } - // 注册方式 - if (!ObjectUtils.isEmpty(registerWay)) { - try { - int registerWayInt = Integer.parseInt(registerWay); - deviceChannel.setRegisterWay(registerWayInt); - }catch (NumberFormatException exception) { - logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); - deviceChannel.setRegisterWay(1); - } - }else { - deviceChannel.setRegisterWay(1); - } - - // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式 - String safetyWay = getText(itemDevice, "SafetyWay"); - if (!ObjectUtils.isEmpty(safetyWay)) { - try { - deviceChannel.setSafetyWay(Integer.parseInt(safetyWay)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay); - } - } - - // 证书序列号(有证书的设备必选) - String certNum = getText(itemDevice, "CertNum"); - if (!ObjectUtils.isEmpty(certNum)) { - deviceChannel.setCertNum(certNum); - } - - // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效 - String certifiable = getText(itemDevice, "Certifiable"); - if (!ObjectUtils.isEmpty(certifiable)) { - try { - deviceChannel.setCertifiable(Integer.parseInt(certifiable)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable); - } - } - - // 无效原因码(有证书且证书无效的设备必选) - String errCode = getText(itemDevice, "ErrCode"); - if (!ObjectUtils.isEmpty(errCode)) { - try { - deviceChannel.setErrCode(Integer.parseInt(errCode)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode); - } - } - - // 证书终止有效期(有证书的设备必选) - String endTime = getText(itemDevice, "EndTime"); - if (!ObjectUtils.isEmpty(endTime)) { - deviceChannel.setEndTime(endTime); - } - - - // 设备/区域/系统IP地址 - String ipAddress = getText(itemDevice, "IPAddress"); - if (!ObjectUtils.isEmpty(ipAddress)) { - deviceChannel.setIpAddress(ipAddress); - } - - // 设备/区域/系统端口 - String port = getText(itemDevice, "Port"); - if (!ObjectUtils.isEmpty(port)) { - try { - deviceChannel.setPort(Integer.parseInt(port)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port); - } - } - - // 设备口令 - String password = getText(itemDevice, "Password"); - if (!ObjectUtils.isEmpty(password)) { - deviceChannel.setPassword(password); - } - - - // 设备状态 - String status = getText(itemDevice, "Status"); - if (status != null) { - // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 - if (status.equalsIgnoreCase("ON") || status.equalsIgnoreCase("On") || status.equalsIgnoreCase("ONLINE") || status.equalsIgnoreCase("OK")) { - deviceChannel.setStatus(true); - } - if (status.equalsIgnoreCase("OFF") || status.equalsIgnoreCase("Off") || status.equalsIgnoreCase("OFFLINE")) { - deviceChannel.setStatus(false); - } - }else { - deviceChannel.setStatus(true); - } -// logger.info("状态字符串: {}", status); -// logger.info("状态结果: {}", deviceChannel.isStatus()); - // 经度 - String longitude = getText(itemDevice, "Longitude"); - if (NumericUtil.isDouble(longitude)) { - deviceChannel.setLongitude(Double.parseDouble(longitude)); - } else { - deviceChannel.setLongitude(0.00); - } - - // 纬度 - String latitude = getText(itemDevice, "Latitude"); - if (NumericUtil.isDouble(latitude)) { - deviceChannel.setLatitude(Double.parseDouble(latitude)); - } else { - deviceChannel.setLatitude(0.00); - } - - deviceChannel.setGpsTime(DateUtil.getNow()); - - // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选 - String ptzType = getText(itemDevice, "PTZType"); - if (ObjectUtils.isEmpty(ptzType)) { - //兼容INFO中的信息 - Element info = itemDevice.element("Info"); - String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType"); - if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){ - try { - deviceChannel.setPtzType(Integer.parseInt(ptzTypeFromInfo)); - }catch (NumberFormatException e){ - logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo); - } - } - } else { - try { - deviceChannel.setPtzType(Integer.parseInt(ptzType)); - }catch (NumberFormatException e){ - logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType); - } - } - - // TODO 摄像机位置类型扩展。 - // 1-省际检查站、 - // 2-党政机关、 - // 3-车站码头、 - // 4-中心广场、 - // 5-体育场馆、 - // 6-商业中心、 - // 7-宗教场所、 - // 8-校园周边、 - // 9-治安复杂区域、 - // 10-交通干线。 - // String positionType = getText(itemDevice, "PositionType"); - - // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。 - // String roomType = getText(itemDevice, "RoomType"); - // TODO 摄像机用途属性 - // String useType = getText(itemDevice, "UseType"); - // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光 - // String supplyLightType = getText(itemDevice, "SupplyLightType"); - // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。 - // String directionType = getText(itemDevice, "DirectionType"); - // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定 - // String resolution = getText(itemDevice, "Resolution"); - - // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4 - // String downloadSpeed = getText(itemDevice, "DownloadSpeed"); - // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层) - // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode"); - // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强 - // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode"); - - - deviceChannel.setSecrecy(secrecy); - break; - } - } - - return deviceChannel; - } +// public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event){ +// DeviceChannel deviceChannel = new DeviceChannel(); +// deviceChannel.setDeviceId(device.getDeviceId()); +// Element channdelIdElement = itemDevice.element("DeviceID"); +// if (channdelIdElement == null) { +// logger.warn("解析Catalog消息时发现缺少 DeviceID"); +// return null; +// } +// String channelId = channdelIdElement.getTextTrim(); +// if (ObjectUtils.isEmpty(channelId)) { +// logger.warn("解析Catalog消息时发现缺少 DeviceID"); +// return null; +// } +// deviceChannel.setDeviceId(channelId); +// if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) { +// // 除了ADD和update情况下需要识别全部内容, +// return deviceChannel; +// } +// Element nameElement = itemDevice.element("Name"); +// // 当通道名称为空时,设置通道名称为通道编码,避免级联时因通道名称为空导致上级接收通道失败 +// if (nameElement != null && StringUtils.isNotBlank(nameElement.getText())) { +// deviceChannel.setName(nameElement.getText()); +// } else { +// deviceChannel.setName(channelId); +// } +// if(channelId.length() <= 8) { +// deviceChannel.setHasAudio(false); +// CivilCodePo parentCode = CivilCodeUtil.INSTANCE.getParentCode(channelId); +// if (parentCode != null) { +// deviceChannel.setParentId(parentCode.getCode()); +// deviceChannel.setCivilCode(parentCode.getCode()); +// }else { +// logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId); +// } +// deviceChannel.setStatus("ON"); +// return deviceChannel; +// }else { +// if(channelId.length() != 20) { +// logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId); +// return null; +// } +// +// int code = Integer.parseInt(channelId.substring(10, 13)); +// if (code == 136 || code == 137 || code == 138) { +// deviceChannel.setHasAudio(true); +// }else { +// deviceChannel.setHasAudio(false); +// } +// // 设备厂商 +// String manufacturer = getText(itemDevice, "Manufacturer"); +// // 设备型号 +// String model = getText(itemDevice, "Model"); +// // 设备归属 +// String owner = getText(itemDevice, "Owner"); +// // 行政区域 +// String civilCode = getText(itemDevice, "CivilCode"); +// // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织 +// String businessGroupID = getText(itemDevice, "BusinessGroupID"); +// // 父设备/区域/系统ID +// String parentID = getText(itemDevice, "ParentID"); +// if (parentID != null && parentID.equalsIgnoreCase("null")) { +// parentID = null; +// } +// // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式 +// String registerWay = getText(itemDevice, "RegisterWay"); +// // 保密属性(必选)缺省为0;0:不涉密,1:涉密 +// String secrecy = getText(itemDevice, "Secrecy"); +// // 安装地址 +// String address = getText(itemDevice, "Address"); +// +// switch (code){ +// case 200: +// // 系统目录 +// if (!ObjectUtils.isEmpty(manufacturer)) { +// deviceChannel.setManufacture(manufacturer); +// } +// if (!ObjectUtils.isEmpty(model)) { +// deviceChannel.setModel(model); +// } +// if (!ObjectUtils.isEmpty(owner)) { +// deviceChannel.setOwner(owner); +// } +// if (!ObjectUtils.isEmpty(civilCode)) { +// deviceChannel.setCivilCode(civilCode); +// deviceChannel.setParentId(civilCode); +// }else { +// if (!ObjectUtils.isEmpty(parentID)) { +// deviceChannel.setParentId(parentID); +// } +// } +// if (!ObjectUtils.isEmpty(address)) { +// deviceChannel.setAddress(address); +// } +// deviceChannel.setStatus(true); +// if (!ObjectUtils.isEmpty(registerWay)) { +// try { +// deviceChannel.setRegisterWay(Integer.parseInt(registerWay)); +// }catch (NumberFormatException exception) { +// logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); +// } +// } +// if (!ObjectUtils.isEmpty(secrecy)) { +// deviceChannel.setSecrecy(secrecy); +// } +// return deviceChannel; +// case 215: +// // 业务分组 +// deviceChannel.setStatus(true); +// if (!ObjectUtils.isEmpty(parentID)) { +// if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) { +// deviceChannel.setParentId(parentID); +// } +// }else { +// logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId"); +// if (!ObjectUtils.isEmpty(civilCode)) { +// deviceChannel.setCivilCode(civilCode); +// } +// } +// break; +// case 216: +// // 虚拟组织 +// deviceChannel.setStatus(true); +// if (!ObjectUtils.isEmpty(businessGroupID)) { +// deviceChannel.setBusinessGroupId(businessGroupID); +// } +// +// if (!ObjectUtils.isEmpty(parentID)) { +// if (parentID.contains("/")) { +// String[] parentIdArray = parentID.split("/"); +// parentID = parentIdArray[parentIdArray.length - 1]; +// } +// deviceChannel.setParentId(parentID); +// }else { +// if (!ObjectUtils.isEmpty(businessGroupID)) { +// deviceChannel.setParentId(businessGroupID); +// } +// } +// break; +// default: +// // 设备目录 +// if (!ObjectUtils.isEmpty(manufacturer)) { +// deviceChannel.setManufacture(manufacturer); +// } +// if (!ObjectUtils.isEmpty(model)) { +// deviceChannel.setModel(model); +// } +// if (!ObjectUtils.isEmpty(owner)) { +// deviceChannel.setOwner(owner); +// } +// if (!ObjectUtils.isEmpty(civilCode) +// && civilCode.length() <= 8 +// && NumberUtils.isParsable(civilCode) +// && civilCode.length()%2 == 0 +// ) { +// deviceChannel.setCivilCode(civilCode); +// } +// if (!ObjectUtils.isEmpty(businessGroupID)) { +// deviceChannel.setBusinessGroupId(businessGroupID); +// } +// +// // 警区 +// String block = getText(itemDevice, "Block"); +// if (!ObjectUtils.isEmpty(block)) { +// deviceChannel.setBlock(block); +// } +// if (!ObjectUtils.isEmpty(address)) { +// deviceChannel.setAddress(address); +// } +// +// if (!ObjectUtils.isEmpty(secrecy)) { +// deviceChannel.setSecrecy(secrecy); +// } +// +// // 当为设备时,是否有子设备(必选)1有,0没有 +// String parental = getText(itemDevice, "Parental"); +// if (!ObjectUtils.isEmpty(parental)) { +// try { +// // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 +// if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) { +// deviceChannel.setParental(0); +// }else { +// deviceChannel.setParental(1); +// } +// }catch (NumberFormatException e) { +// logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental); +// } +// } +// // 父设备/区域/系统ID +// +// if (!ObjectUtils.isEmpty(parentID) ) { +// if (parentID.contains("/")) { +// String[] parentIdArray = parentID.split("/"); +// deviceChannel.setParentId(parentIdArray[parentIdArray.length - 1]); +// }else { +// if (parentID.length()%2 == 0) { +// deviceChannel.setParentId(parentID); +// }else { +// logger.warn("[xml解析] 不规范的parentID:{}, 已舍弃", parentID); +// } +// } +// }else { +// if (!ObjectUtils.isEmpty(businessGroupID)) { +// deviceChannel.setParentId(businessGroupID); +// }else { +// if (!ObjectUtils.isEmpty(deviceChannel.getCivilCode())) { +// deviceChannel.setParentId(deviceChannel.getCivilCode()); +// } +// } +// } +// // 注册方式 +// if (!ObjectUtils.isEmpty(registerWay)) { +// try { +// int registerWayInt = Integer.parseInt(registerWay); +// deviceChannel.setRegisterWay(registerWayInt); +// }catch (NumberFormatException exception) { +// logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); +// deviceChannel.setRegisterWay(1); +// } +// }else { +// deviceChannel.setRegisterWay(1); +// } +// +// // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式 +// String safetyWay = getText(itemDevice, "SafetyWay"); +// if (!ObjectUtils.isEmpty(safetyWay)) { +// try { +// deviceChannel.setSafetyWay(Integer.parseInt(safetyWay)); +// }catch (NumberFormatException e) { +// logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay); +// } +// } +// +// // 证书序列号(有证书的设备必选) +// String certNum = getText(itemDevice, "CertNum"); +// if (!ObjectUtils.isEmpty(certNum)) { +// deviceChannel.setCertNum(certNum); +// } +// +// // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效 +// String certifiable = getText(itemDevice, "Certifiable"); +// if (!ObjectUtils.isEmpty(certifiable)) { +// try { +// deviceChannel.setCertifiable(Integer.parseInt(certifiable)); +// }catch (NumberFormatException e) { +// logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable); +// } +// } +// +// // 无效原因码(有证书且证书无效的设备必选) +// String errCode = getText(itemDevice, "ErrCode"); +// if (!ObjectUtils.isEmpty(errCode)) { +// try { +// deviceChannel.setErrCode(Integer.parseInt(errCode)); +// }catch (NumberFormatException e) { +// logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode); +// } +// } +// +// // 证书终止有效期(有证书的设备必选) +// String endTime = getText(itemDevice, "EndTime"); +// if (!ObjectUtils.isEmpty(endTime)) { +// deviceChannel.setEndTime(endTime); +// } +// +// +// // 设备/区域/系统IP地址 +// String ipAddress = getText(itemDevice, "IPAddress"); +// if (!ObjectUtils.isEmpty(ipAddress)) { +// deviceChannel.setIpAddress(ipAddress); +// } +// +// // 设备/区域/系统端口 +// String port = getText(itemDevice, "Port"); +// if (!ObjectUtils.isEmpty(port)) { +// try { +// deviceChannel.setPort(Integer.parseInt(port)); +// }catch (NumberFormatException e) { +// logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port); +// } +// } +// +// // 设备口令 +// String password = getText(itemDevice, "Password"); +// if (!ObjectUtils.isEmpty(password)) { +// deviceChannel.setPassword(password); +// } +// +// +// // 设备状态 +// String status = getText(itemDevice, "Status"); +// if (status != null) { +// // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 +// if (status.equalsIgnoreCase("ON") || status.equalsIgnoreCase("On") || status.equalsIgnoreCase("ONLINE") || status.equalsIgnoreCase("OK")) { +// deviceChannel.setStatus(true); +// } +// if (status.equalsIgnoreCase("OFF") || status.equalsIgnoreCase("Off") || status.equalsIgnoreCase("OFFLINE")) { +// deviceChannel.setStatus(false); +// } +// }else { +// deviceChannel.setStatus(true); +// } +//// logger.info("状态字符串: {}", status); +//// logger.info("状态结果: {}", deviceChannel.isStatus()); +// // 经度 +// String longitude = getText(itemDevice, "Longitude"); +// if (NumericUtil.isDouble(longitude)) { +// deviceChannel.setLongitude(Double.parseDouble(longitude)); +// } else { +// deviceChannel.setLongitude(0.00); +// } +// +// // 纬度 +// String latitude = getText(itemDevice, "Latitude"); +// if (NumericUtil.isDouble(latitude)) { +// deviceChannel.setLatitude(Double.parseDouble(latitude)); +// } else { +// deviceChannel.setLatitude(0.00); +// } +// +// deviceChannel.setGpsTime(DateUtil.getNow()); +// +// // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选 +// String ptzType = getText(itemDevice, "PTZType"); +// if (ObjectUtils.isEmpty(ptzType)) { +// //兼容INFO中的信息 +// Element info = itemDevice.element("Info"); +// String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType"); +// if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){ +// try { +// deviceChannel.setPtzType(Integer.parseInt(ptzTypeFromInfo)); +// }catch (NumberFormatException e){ +// logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo); +// } +// } +// } else { +// try { +// deviceChannel.setPtzType(Integer.parseInt(ptzType)); +// }catch (NumberFormatException e){ +// logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType); +// } +// } +// +// // TODO 摄像机位置类型扩展。 +// // 1-省际检查站、 +// // 2-党政机关、 +// // 3-车站码头、 +// // 4-中心广场、 +// // 5-体育场馆、 +// // 6-商业中心、 +// // 7-宗教场所、 +// // 8-校园周边、 +// // 9-治安复杂区域、 +// // 10-交通干线。 +// // String positionType = getText(itemDevice, "PositionType"); +// +// // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。 +// // String roomType = getText(itemDevice, "RoomType"); +// // TODO 摄像机用途属性 +// // String useType = getText(itemDevice, "UseType"); +// // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光 +// // String supplyLightType = getText(itemDevice, "SupplyLightType"); +// // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。 +// // String directionType = getText(itemDevice, "DirectionType"); +// // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定 +// // String resolution = getText(itemDevice, "Resolution"); +// +// // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4 +// // String downloadSpeed = getText(itemDevice, "DownloadSpeed"); +// // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层) +// // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode"); +// // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强 +// // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode"); +// +// +// deviceChannel.setSecrecy(secrecy); +// break; +// } +// } +// +// return deviceChannel; +// } /** * 新增方法支持内部嵌套 @@ -672,6 +664,46 @@ public class XmlUtil { return t; } + public static T elementDecode(Element element, Class clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + Field[] fields = clazz.getDeclaredFields(); + T t = clazz.getDeclaredConstructor().newInstance(); + for (Field field : fields) { + ReflectionUtils.makeAccessible(field); + MessageElement annotation = field.getAnnotation(MessageElement.class); + if (annotation == null) { + continue; + } + String value = annotation.value(); + boolean subVal = value.contains("."); + Element element1 = element.element(value); + if (element1 == null) { + continue; + } + if (!subVal) { + // 无下级数据 + Object fieldVal = element1.isTextOnly() ? element1.getText() : loadElement(element1, field.getType()); + Object o = simpleTypeDeal(field.getType(), fieldVal); + ReflectionUtils.setField(field, t, o); + } else { + String[] pathArray = value.split("."); + Element subElement = element1; + for (String path : pathArray) { + subElement = subElement.element(path); + if (subElement == null) { + break; + } + } + if (subElement == null) { + continue; + } + Object fieldVal = subElement.isTextOnly() ? subElement.getText() : loadElement(subElement, field.getType()); + Object o = simpleTypeDeal(field.getType(), fieldVal); + ReflectionUtils.setField(field, t, o); + } + } + return t; + } + /** * 简单类型处理 * diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java index 2379321a..2f51a3e2 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java +++ b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.media.event.media; import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; +import com.genersoft.iot.vmp.vmanager.bean.StreamContent; /** * 流到来事件 @@ -19,7 +20,8 @@ public class MediaArrivalEvent extends MediaEvent { mediaArrivalEvent.setStream(hookParam.getStream()); mediaArrivalEvent.setMediaServer(mediaServer); mediaArrivalEvent.setSchema(hookParam.getSchema()); - mediaArrivalEvent.setCallId(hookParam.getCallId()); + mediaArrivalEvent.setSchema(hookParam.getSchema()); + mediaArrivalEvent.setHookParam(hookParam); return mediaArrivalEvent; } @@ -27,6 +29,10 @@ public class MediaArrivalEvent extends MediaEvent { private String callId; + private OnStreamChangedHookParam hookParam; + + private StreamContent streamInfo; + public MediaInfo getMediaInfo() { return mediaInfo; } @@ -43,4 +49,20 @@ public class MediaArrivalEvent extends MediaEvent { public void setCallId(String callId) { this.callId = callId; } + + public OnStreamChangedHookParam getHookParam() { + return hookParam; + } + + public void setHookParam(OnStreamChangedHookParam hookParam) { + this.hookParam = hookParam; + } + + public StreamContent getStreamInfo() { + return streamInfo; + } + + public void setStreamInfo(StreamContent streamInfo) { + this.streamInfo = streamInfo; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java index 2413f567..1e1fcca1 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java @@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.media.event.mediaServer; import com.genersoft.iot.vmp.service.IPlayService; import com.genersoft.iot.vmp.service.IStreamProxyService; -import com.genersoft.iot.vmp.service.IStreamPushService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -23,9 +22,6 @@ public class MediaServerStatusEventListener { private final static Logger logger = LoggerFactory.getLogger(MediaServerStatusEventListener.class); - @Autowired - private IStreamPushService streamPushService; - @Autowired private IStreamProxyService streamProxyService; @@ -36,7 +32,6 @@ public class MediaServerStatusEventListener { @EventListener public void onApplicationEvent(MediaServerOnlineEvent event) { logger.info("[媒体节点] 上线 ID:" + event.getMediaServerId()); - streamPushService.zlmServerOnline(event.getMediaServerId()); streamProxyService.zlmServerOnline(event.getMediaServerId()); playService.zlmServerOnline(event.getMediaServerId()); } @@ -48,7 +43,6 @@ public class MediaServerStatusEventListener { logger.info("[媒体节点] 离线,ID:" + event.getMediaServerId()); // 处理ZLM离线 streamProxyService.zlmServerOffline(event.getMediaServerId()); - streamPushService.zlmServerOffline(event.getMediaServerId()); playService.zlmServerOffline(event.getMediaServerId()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java index a0b33413..d8f5ba95 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java @@ -809,6 +809,13 @@ public class MediaServerServiceImpl implements IMediaServerService { streamInfoResult.setRtc(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam, isPlay); streamInfoResult.setMediaInfo(mediaInfo); + + if (!"broadcast".equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaServer.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaServer.getTranscodeSuffix())) { + String newStream = stream + "_" + mediaServer.getTranscodeSuffix(); + mediaServer.setTranscodeSuffix(null); + StreamInfo transcodeStreamInfo = getStreamInfoByAppAndStream(mediaServer, app, newStream, null, addr, callId, isPlay); + streamInfoResult.setTranscodeStream(transcodeStreamInfo); + } return streamInfoResult; } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPush.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPush.java index 41d4af96..eeb444dc 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPush.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPush.java @@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import org.jetbrains.annotations.NotNull; +import org.springframework.util.ObjectUtils; @Data @@ -102,6 +103,16 @@ public class StreamPush extends CommonGBChannel implements Comparable gbStreams, String type); + void sendCatalogMsg(CommonGBChannel gbStream, String type); + void sendCatalogMsgs(List gbStreams, String type); /** * 修改gbId或name diff --git a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java b/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java index b99106e7..6520f605 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java @@ -40,12 +40,14 @@ public interface IStreamPushService { StreamPush getPush(String app, String streamId); + boolean stop(StreamPush streamPush); + /** * 停止一路推流 * @param app 应用名 * @param stream 流ID */ - boolean stop(String app, String stream); + boolean stopByAppAndStream(String app, String stream); /** * 新的节点加入 @@ -100,6 +102,8 @@ public interface IStreamPushService { */ boolean add(StreamPush stream); + boolean update(StreamPush stream); + /** * 获取全部的app+Streanm 用于判断推流列表是新增还是修改 * @return @@ -116,4 +120,12 @@ public interface IStreamPushService { void updatePush(OnStreamChangedHookParam param); + + Map getAllGBId(); + + void updateStatus(StreamPush push); + + void deleteByAppAndStream(String app, String stream); + + void updatePushStatus(Integer streamPushId, boolean pushIng); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java index 46b70f18..0f199378 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java @@ -157,16 +157,16 @@ public class GbStreamServiceImpl implements IGbStreamService { } @Override - public void sendCatalogMsg(GbStream gbStream, String type) { - if (gbStream == null || type == null) { + public void sendCatalogMsg(CommonGBChannel channel, String type) { + if (channel == null || type == null) { logger.warn("[发送目录订阅]类型:流信息或类型为NULL"); return; } - List gbStreams = new ArrayList<>(); - if (gbStream.getGbId() != null) { - gbStreams.add(gbStream); + List gbStreams = new ArrayList<>(); + if (channel.getGbDeviceId() != null) { + gbStreams.add(channel); }else { - GbStream gbStreamIndb = gbStreamMapper.selectOne(gbStream.getApp(), gbStream.getStream()); + GbStream gbStreamIndb = gbStreamMapper.selectOne(channel.getApp(), channel.getStream()); if (gbStreamIndb != null && gbStreamIndb.getGbId() != null){ gbStreams.add(gbStreamIndb); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java index 0d8a8ec6..31dfe4cc 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java @@ -5,29 +5,33 @@ import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.MediaConfig; import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; import com.genersoft.iot.vmp.media.bean.MediaInfo; +import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent; +import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOfflineEvent; +import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOnlineEvent; import com.genersoft.iot.vmp.media.service.IMediaServerService; -import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.StreamPush; -import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.media.zlm.dto.hook.OriginType; -import com.genersoft.iot.vmp.service.IGbStreamService; import com.genersoft.iot.vmp.service.IStreamPushService; import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.dao.*; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; +import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; +import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -36,21 +40,17 @@ import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.TransactionDefinition; -import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ObjectUtils; import java.util.*; import java.util.stream.Collectors; @Service +@Slf4j @DS("master") public class StreamPushServiceImpl implements IStreamPushService { - private final static Logger logger = LoggerFactory.getLogger(StreamPushServiceImpl.class); - - @Autowired - private GbStreamMapper gbStreamMapper; - @Autowired private StreamPushMapper streamPushMapper; @@ -66,9 +66,6 @@ public class StreamPushServiceImpl implements IStreamPushService { @Autowired private PlatformGbStreamMapper platformGbStreamMapper; - @Autowired - private IGbStreamService gbStreamService; - @Autowired private EventPublisher eventPublisher; @@ -90,6 +87,9 @@ public class StreamPushServiceImpl implements IStreamPushService { @Autowired private MediaConfig mediaConfig; + @Autowired + private IGbChannelService gbChannelService; + /** * 流到来的处理 */ @@ -113,31 +113,25 @@ public class StreamPushServiceImpl implements IStreamPushService { streamAuthorityInfo.setOriginType(mediaInfo.getOriginType()); } redisCatchStorage.updateStreamAuthorityInfo(event.getApp(), event.getStream(), streamAuthorityInfo); - StreamPush transform = StreamPush.getInstance(event, userSetting.getServerId()); - transform.setPushIng(true); - transform.setUpdateTime(DateUtil.getNow()); - transform.setPushTime(DateUtil.getNow()); - transform.setSelf(true); - StreamPush pushInDb = getPush(event.getApp(), event.getStream()); - if (pushInDb == null) { - transform.setCreateTime(DateUtil.getNow()); - streamPushMapper.add(transform); + + StreamPush streamPushInDb = getPush(event.getApp(), event.getStream()); + if (streamPushInDb == null) { + StreamPush streamPush = StreamPush.getInstance(event, userSetting.getServerId()); + streamPush.setPushIng(true); + streamPush.setUpdateTime(DateUtil.getNow()); + streamPush.setPushTime(DateUtil.getNow()); + streamPush.setSelf(true); + add(streamPush); }else { - streamPushMapper.update(transform); - gbStreamMapper.updateMediaServer(event.getApp(), event.getStream(), event.getMediaServer().getId()); + updatePushStatus(streamPushInDb.getId(), true); } - // TODO 相关的事件自行管理,不需要写入ZLMMediaListManager -// ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(transform.getApp(), transform.getStream()); -// if ( channelOnlineEventLister != null) { -// try { -// channelOnlineEventLister.run(transform.getApp(), transform.getStream(), transform.getServerId());; -// } catch (ParseException e) { -// logger.error("addPush: ", e); -// } -// removedChannelOnlineEventLister(transform.getApp(), transform.getStream()); -// } // 冗余数据,自己系统中自用 - redisCatchStorage.addPushListItem(event.getApp(), event.getStream(), event); + if (!"broadcast".equals(event.getApp()) && !"talk".equals(event.getApp())) { + StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream( + event.getMediaServer(), event.getApp(), event.getStream(), event.getMediaInfo(), event.getCallId()); + event.getHookParam().setStreamInfo(new StreamContent(streamInfo)); + redisCatchStorage.addPushListItem(event.getApp(), event.getStream(), event); + } // 发送流变化redis消息 JSONObject jsonObject = new JSONObject(); @@ -155,6 +149,7 @@ public class StreamPushServiceImpl implements IStreamPushService { @Async("taskExecutor") @EventListener public void onApplicationEvent(MediaDepartureEvent event) { + // 兼容流注销时类型从redis记录获取 MediaInfo mediaInfo = redisCatchStorage.getStreamInfo( event.getApp(), event.getStream(), event.getMediaServer().getId()); @@ -176,49 +171,36 @@ public class StreamPushServiceImpl implements IStreamPushService { redisCatchStorage.sendStreamChangeMsg(type, jsonObject); } } - GbStream gbStream = gbStreamMapper.selectOne(event.getApp(), event.getStream()); - if (gbStream != null) { + StreamPush push = getPush(event.getApp(), event.getStream()); + push.setPushIng(false); + if (push.getGbDeviceId() != null) { if (userSetting.isUsePushingAsStatus()) { - streamPushMapper.updatePushStatus(event.getApp(), event.getStream(), false); - eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); + push.setGbStatus(false); + updateStatus(push); +// streamPushMapper.updatePushStatus(event.getApp(), event.getStream(), false); +// eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); } }else { - streamPushMapper.del(event.getApp(), event.getStream()); + deleteByAppAndStream(event.getApp(), event.getStream()); } } - - private List handleJSON(List streamInfoList) { - if (streamInfoList == null || streamInfoList.isEmpty()) { - return null; - } - Map result = new HashMap<>(); - for (StreamInfo streamInfo : streamInfoList) { - // 不保存国标推理以及拉流代理的流 - if (streamInfo.getOriginType() == OriginType.RTSP_PUSH.ordinal() - || streamInfo.getOriginType() == OriginType.RTMP_PUSH.ordinal() - || streamInfo.getOriginType() == OriginType.RTC_PUSH.ordinal() ) { - String key = streamInfo.getApp() + "_" + streamInfo.getStream(); - StreamPush streamPushItem = result.get(key); - if (streamPushItem == null) { - streamPushItem = streamPushItem.getInstance(streamInfo); - result.put(key, streamPushItem); - } - } - } - return new ArrayList<>(result.values()); + /** + * 流媒体节点上线 + */ + @Async("taskExecutor") + @EventListener + public void onApplicationEvent(MediaServerOnlineEvent event) { + zlmServerOnline(event.getMediaServerId()); } - @Override - public StreamPush transform(OnStreamChangedHookParam item) { - StreamPush streamPushItem = new StreamPush(); - streamPushItem.setApp(item.getApp()); - streamPushItem.setMediaServerId(item.getMediaServerId()); - streamPushItem.setStream(item.getStream()); - streamPushItem.setCreateTime(DateUtil.getNow()); - streamPushItem.setVhost(item.getVhost()); - streamPushItem.setServerId(item.getSeverId()); - return streamPushItem; + /** + * 流媒体节点离线 + */ + @Async("taskExecutor") + @EventListener + public void onApplicationEvent(MediaServerOfflineEvent event) { + zlmServerOffline(event.getMediaServerId()); } @Override @@ -233,56 +215,115 @@ public class StreamPushServiceImpl implements IStreamPushService { return streamPushMapper.selectAllByMediaServerIdWithOutGbID(mediaServerId); } + @Override - public boolean saveToGB(GbStream stream) { - stream.setStreamType("push"); - stream.setStatus(true); + public StreamPush getPush(String app, String stream) { + return streamPushMapper.selectByAppAndStream(app, stream); + } + + @Override + @Transactional + public boolean add(StreamPush stream) { + log.info("[添加推流] app: {}, stream: {}, 国标编号: {}", stream.getApp(), stream.getStream(), stream.getGbDeviceId()); + stream.setUpdateTime(DateUtil.getNow()); stream.setCreateTime(DateUtil.getNow()); - stream.setStreamType("push"); - stream.setMediaServerId(mediaConfig.getId()); - int add = gbStreamMapper.add(stream); - return add > 0; - } - - @Override - public boolean removeFromGB(GbStream stream) { - // 判断是否需要发送事件 - gbStreamService.sendCatalogMsg(stream, CatalogEvent.DEL); - platformGbStreamMapper.delByAppAndStream(stream.getApp(), stream.getStream()); - int del = gbStreamMapper.del(stream.getApp(), stream.getStream()); - MediaServer mediaInfo = mediaServerService.getOne(stream.getMediaServerId()); - List mediaList = mediaServerService.getMediaList(mediaInfo, stream.getApp(), stream.getStream(), null); - if (mediaList != null && mediaList.isEmpty()) { - streamPushMapper.del(stream.getApp(), stream.getStream()); + int addResult = streamPushMapper.add(stream); + if (addResult <= 0) { + return false; } - return del > 0; + if (ObjectUtils.isEmpty(stream.getGbDeviceId())) { + return true; + } + CommonGBChannel channel = gbChannelService.queryByDeviceId(stream.getGbDeviceId()); + if (channel != null) { + log.info("[添加推流]失败,国标编号已存在: {} app: {}, stream: {}, ", stream.getGbDeviceId(), stream.getApp(), stream.getStream()); + } + int addChannelResult = gbChannelService.add(stream.getCommonGBChannel()); + return addChannelResult > 0; + } + + @Override + @Transactional + public void deleteByAppAndStream(String app, String stream) { + log.info("[删除推流] app: {}, stream: {}, ", app, stream); + StreamPush streamPush = streamPushMapper.selectByAppAndStream(app, stream); + if (streamPush == null) { + log.info("[删除推流]失败, 不存在 app: {}, stream: {}, ", app, stream); + return; + } + if (streamPush.isPushIng()) { + stop(streamPush); + } + if (streamPush.getGbId() > 0) { + gbChannelService.delete(streamPush.getGbId()); + } + } + @Override + @Transactional + public boolean update(StreamPush streamPush) { + log.info("[更新推流]:id: {}, app: {}, stream: {}, ", streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + assert streamPush.getId() != null; + streamPush.setUpdateTime(DateUtil.getNow()); + streamPushMapper.update(streamPush); + if (streamPush.getGbId() > 0) { + gbChannelService.update(streamPush.getCommonGBChannel()); + } + return true; } @Override - public StreamPush getPush(String app, String streamId) { - return streamPushMapper.selectOne(app, streamId); + @Transactional + public boolean stop(StreamPush streamPush) { + log.info("[主动停止推流] id: {}, app: {}, stream: {}, ", streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + MediaServer mediaServer = null; + if (streamPush.getMediaServerId() == null) { + log.info("[主动停止推流]未找到使用MediaServer,开始自动检索 id: {}, app: {}, stream: {}, ", streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + mediaServer = mediaServerService.getMediaServerByAppAndStream(streamPush.getApp(), streamPush.getStream()); + if (mediaServer != null) { + log.info("[主动停止推流] 检索到MediaServer为{}, id: {}, app: {}, stream: {}, ", mediaServer.getId(), streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + }else { + log.info("[主动停止推流]未找到使用MediaServer id: {}, app: {}, stream: {}, ", streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + } + }else { + mediaServer = mediaServerService.getOne(streamPush.getMediaServerId()); + if (mediaServer == null) { + log.info("[主动停止推流]未找到使用的MediaServer: {},开始自动检索 id: {}, app: {}, stream: {}, ",streamPush.getMediaServerId(), streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + mediaServer = mediaServerService.getMediaServerByAppAndStream(streamPush.getApp(), streamPush.getStream()); + if (mediaServer != null) { + log.info("[主动停止推流] 检索到MediaServer为{}, id: {}, app: {}, stream: {}, ", mediaServer.getId(), streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + }else { + log.info("[主动停止推流]未找到使用MediaServer id: {}, app: {}, stream: {}, ", streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + } + } + } + if (mediaServer != null) { + mediaServerService.closeStreams(mediaServer, streamPush.getApp(), streamPush.getStream()); + } + streamPush.setPushIng(false); + if (userSetting.isUsePushingAsStatus()) { + streamPush.setGbStatus(false); + gbChannelService.offline(streamPush.getCommonGBChannel()); + } + gbChannelService.closeSend(streamPush.getCommonGBChannel()); + streamPush.setUpdateTime(DateUtil.getNow()); + streamPushMapper.update(streamPush); + return true; } @Override - public boolean stop(String app, String stream) { - logger.info("[推流 ] 停止流: {}/{}", app, stream); - StreamPush streamPushItem = streamPushMapper.selectOne(app, stream); + @Transactional + public boolean stopByAppAndStream(String app, String stream) { + log.info("[主动停止推流] : app: {}, stream: {}, ", app, stream); + StreamPush streamPushItem = streamPushMapper.selectByAppAndStream(app, stream); if (streamPushItem != null) { - gbStreamService.sendCatalogMsg(streamPushItem, CatalogEvent.DEL); - } - - platformGbStreamMapper.delByAppAndStream(app, stream); - gbStreamMapper.del(app, stream); - int delStream = streamPushMapper.del(app, stream); - if (delStream > 0) { - MediaServer mediaServerItem = mediaServerService.getOne(streamPushItem.getMediaServerId()); - mediaServerService.closeStreams(mediaServerItem,app, stream); + stop(streamPushItem); } return true; } @Override + @Transactional public void zlmServerOnline(String mediaServerId) { // 同步zlm推流信息 MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId); @@ -295,14 +336,14 @@ public class StreamPushServiceImpl implements IStreamPushService { // redis记录 List mediaInfoList = redisCatchStorage.getStreams(mediaServerId, "PUSH"); Map streamInfoPushItemMap = new HashMap<>(); - if (pushList.size() > 0) { + if (!pushList.isEmpty()) { for (StreamPush streamPushItem : pushList) { if (ObjectUtils.isEmpty(streamPushItem.getGbId())) { pushItemMap.put(streamPushItem.getApp() + streamPushItem.getStream(), streamPushItem); } } } - if (mediaInfoList.size() > 0) { + if (!mediaInfoList.isEmpty()) { for (MediaInfo mediaInfo : mediaInfoList) { streamInfoPushItemMap.put(mediaInfo.getApp() + mediaInfo.getStream(), mediaInfo); } @@ -325,26 +366,33 @@ public class StreamPushServiceImpl implements IStreamPushService { streamAuthorityInfoInfoMap.remove(streamPushItem.getApp() + streamPushItem.getStream()); } } - List offlinePushItems = new ArrayList<>(pushItemMap.values()); - if (offlinePushItems.size() > 0) { - String type = "PUSH"; - int runLimit = 300; - if (offlinePushItems.size() > runLimit) { - for (int i = 0; i < offlinePushItems.size(); i += runLimit) { - int toIndex = i + runLimit; - if (i + runLimit > offlinePushItems.size()) { - toIndex = offlinePushItems.size(); - } - List streamPushItemsSub = offlinePushItems.subList(i, toIndex); - streamPushMapper.delAll(streamPushItemsSub); - } - }else { - streamPushMapper.delAll(offlinePushItems); + List changedStreamPushList = new ArrayList<>(pushItemMap.values()); + if (!changedStreamPushList.isEmpty()) { + for (StreamPush streamPush : changedStreamPushList) { + stop(streamPush); } - } + + +// if (!changedStreamPushList.isEmpty()) { +// String type = "PUSH"; +// int runLimit = 300; +// if (changedStreamPushList.size() > runLimit) { +// for (int i = 0; i < changedStreamPushList.size(); i += runLimit) { +// int toIndex = i + runLimit; +// if (i + runLimit > changedStreamPushList.size()) { +// toIndex = changedStreamPushList.size(); +// } +// List streamPushItemsSub = changedStreamPushList.subList(i, toIndex); +// streamPushMapper.delAll(streamPushItemsSub); +// } +// }else { +// streamPushMapper.delAll(changedStreamPushList); +// } +// +// } Collection mediaInfos = streamInfoPushItemMap.values(); - if (mediaInfos.size() > 0) { + if (!mediaInfos.isEmpty()) { String type = "PUSH"; for (MediaInfo mediaInfo : mediaInfos) { JSONObject jsonObject = new JSONObject(); @@ -362,7 +410,7 @@ public class StreamPushServiceImpl implements IStreamPushService { } Collection streamAuthorityInfos = streamAuthorityInfoInfoMap.values(); - if (streamAuthorityInfos.size() > 0) { + if (!streamAuthorityInfos.isEmpty()) { for (StreamAuthorityInfo streamAuthorityInfo : streamAuthorityInfos) { // 移除redis内流的信息 redisCatchStorage.removeStreamAuthorityInfo(streamAuthorityInfo.getApp(), streamAuthorityInfo.getStream()); @@ -371,19 +419,24 @@ public class StreamPushServiceImpl implements IStreamPushService { } @Override + @Transactional public void zlmServerOffline(String mediaServerId) { - List streamPushItems = streamPushMapper.selectAllByMediaServerIdWithOutGbID(mediaServerId); - // 移除没有GBId的推流 - streamPushMapper.deleteWithoutGBId(mediaServerId); - gbStreamMapper.deleteWithoutGBId("push", mediaServerId); - // 其他的流设置未启用 - streamPushMapper.updateStatusByMediaServerId(mediaServerId, false); - streamProxyMapper.updateStatusByMediaServerId(mediaServerId, false); + List streamPushItems = streamPushMapper.selectAllByMediaServerId(mediaServerId); + if (!streamPushItems.isEmpty()) { + for (StreamPush streamPushItem : streamPushItems) { + stop(streamPushItem); + } + } +// // 移除没有GBId的推流 +// streamPushMapper.deleteWithoutGBId(mediaServerId); +// // 其他的流设置未启用 +// streamPushMapper.updateStatusByMediaServerId(mediaServerId, false); +// streamProxyMapper.updateStatusByMediaServerId(mediaServerId, false); // 发送流停止消息 String type = "PUSH"; // 发送redis消息 List mediaInfoList = redisCatchStorage.getStreams(mediaServerId, type); - if (mediaInfoList.size() > 0) { + if (!mediaInfoList.isEmpty()) { for (MediaInfo mediaInfo : mediaInfoList) { // 移除redis内流的信息 redisCatchStorage.removeStream(mediaServerId, type, mediaInfo.getApp(), mediaInfo.getStream()); @@ -402,41 +455,16 @@ public class StreamPushServiceImpl implements IStreamPushService { } @Override - public void clean() { - - } - - @Override - public boolean saveToRandomGB() { - List streamPushItems = streamPushMapper.selectAll(); - long gbId = 100001; - for (StreamPush streamPushItem : streamPushItems) { - streamPushItem.setStreamType("push"); - streamPushItem.setStatus(true); - streamPushItem.setGbId("34020000004111" + gbId); - streamPushItem.setCreateTime(DateUtil.getNow()); - gbId ++; - } - int limitCount = 30; - - if (streamPushItems.size() > limitCount) { - for (int i = 0; i < streamPushItems.size(); i += limitCount) { - int toIndex = i + limitCount; - if (i + limitCount > streamPushItems.size()) { - toIndex = streamPushItems.size(); - } - gbStreamMapper.batchAdd(streamPushItems.subList(i, toIndex)); - } - }else { - gbStreamMapper.batchAdd(streamPushItems); - } - return true; - } - - @Override + @Transactional public void batchAdd(List streamPushItems) { streamPushMapper.addAll(streamPushItems); - gbStreamMapper.batchAdd(streamPushItems); + List commonGBChannels = new ArrayList<>(); + for (StreamPush streamPush : streamPushItems) { + if (ObjectUtils.isEmpty(streamPush.getGbDeviceId())) { + commonGBChannels.add(streamPush.getCommonGBChannel()); + } + } + gbChannelService.batchAdd(commonGBChannels); } @@ -494,7 +522,7 @@ public class StreamPushServiceImpl implements IStreamPushService { // 不存在这个平台,则忽略导入此关联关系 if (platformInfoMap.get(platFormInfoArray[0]) == null || platformInfoMap.get(platFormInfoArray[0]).get(platFormInfoArray[1]) == null) { - logger.info("导入数据时不存在平台或目录{}/{},已导入未分配", platFormInfoArray[0], platFormInfoArray[1] ); + log.info("导入数据时不存在平台或目录{}/{},已导入未分配", platFormInfoArray[0], platFormInfoArray[1] ); continue; } streamPushItemForPlatform.setPlatformId(platFormInfoArray[0]); @@ -579,33 +607,6 @@ public class StreamPushServiceImpl implements IStreamPushService { eventPublisher.catalogEventPublishForStream(null, onlinePushers, CatalogEvent.ON); } - @Override - public boolean add(StreamPush stream) { - stream.setUpdateTime(DateUtil.getNow()); - stream.setCreateTime(DateUtil.getNow()); - stream.setServerId(userSetting.getServerId()); - stream.setMediaServerId(mediaConfig.getId()); - stream.setSelf(true); - stream.setPushIng(true); - - // 放在事务内执行 - boolean result = false; - TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); - try { - int addStreamResult = streamPushMapper.add(stream); - if (!ObjectUtils.isEmpty(stream.getGbId())) { - stream.setStreamType("push"); - gbStreamMapper.add(stream); - } - dataSourceTransactionManager.commit(transactionStatus); - result = true; - }catch (Exception e) { - logger.error("批量移除流与平台的关系时错误", e); - dataSourceTransactionManager.rollback(transactionStatus); - } - return result; - } - @Override public List getAllAppAndStream() { @@ -626,19 +627,45 @@ public class StreamPushServiceImpl implements IStreamPushService { } @Override - public void updatePush(OnStreamChangedHookParam param) { - StreamPush transform = transform(param); - StreamPush pushInDb = getPush(param.getApp(), param.getStream()); - transform.setPushIng(param.isRegist()); - transform.setUpdateTime(DateUtil.getNow()); - transform.setPushTime(DateUtil.getNow()); - transform.setSelf(userSetting.getServerId().equals(param.getSeverId())); - if (pushInDb == null) { - transform.setCreateTime(DateUtil.getNow()); - streamPushMapper.add(transform); - }else { - streamPushMapper.update(transform); - gbStreamMapper.updateMediaServer(param.getApp(), param.getStream(), param.getMediaServerId()); - } + public Map getAllGBId() { + return streamPushMapper.getAllGBId(); } + + @Override + public void updateStatus(StreamPush push) { + + } + + + + @Override + public void updatePushStatus(Integer streamPushId, boolean pushIng) { + streamPushInDb.setPushIng(true); + if (userSetting.isUsePushingAsStatus()) { + streamPushInDb.setGbStatus(true); + } + streamPushInDb.setPushTime(DateUtil.getNow()); + } + + private List handleJSON(List streamInfoList) { + if (streamInfoList == null || streamInfoList.isEmpty()) { + return null; + } + Map result = new HashMap<>(); + for (StreamInfo streamInfo : streamInfoList) { + // 不保存国标推理以及拉流代理的流 + if (streamInfo.getOriginType() == OriginType.RTSP_PUSH.ordinal() + || streamInfo.getOriginType() == OriginType.RTMP_PUSH.ordinal() + || streamInfo.getOriginType() == OriginType.RTC_PUSH.ordinal() ) { + String key = streamInfo.getApp() + "_" + streamInfo.getStream(); + StreamPush streamPushItem = result.get(key); + if (streamPushItem == null) { + streamPushItem = streamPushItem.getInstance(streamInfo); + result.put(key, streamPushItem); + } + } + } + return new ArrayList<>(result.values()); + } + } diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java index d0104756..d9c35e27 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java @@ -3,9 +3,8 @@ package com.genersoft.iot.vmp.service.redisMsg; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.service.IStreamPushService; +import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.connection.Message; @@ -17,14 +16,13 @@ import java.util.concurrent.ConcurrentLinkedQueue; /** * 接收来自redis的关闭流更新通知 + * 消息举例: PUBLISH VM_MSG_STREAM_PUSH_CLOSE "{'app': 'live', 'stream': 'stream'}" * @author lin */ +@Slf4j @Component public class RedisCloseStreamMsgListener implements MessageListener { - private final static Logger logger = LoggerFactory.getLogger(RedisCloseStreamMsgListener.class); - - @Autowired private IStreamPushService pushService; @@ -46,11 +44,10 @@ public class RedisCloseStreamMsgListener implements MessageListener { JSONObject jsonObject = JSON.parseObject(msg.getBody()); String app = jsonObject.getString("app"); String stream = jsonObject.getString("stream"); - pushService.stop(app, stream); - + pushService.stopByAppAndStream(app, stream); }catch (Exception e) { - logger.warn("[REDIS的关闭推流通知] 发现未处理的异常, \r\n{}", JSON.toJSONString(message)); - logger.error("[REDIS的关闭推流通知] 异常内容: ", e); + log.warn("[REDIS的关闭推流通知] 发现未处理的异常, \r\n{}", JSON.toJSONString(message)); + log.error("[REDIS的关闭推流通知] 异常内容: ", e); } } }); diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java index 48b08eac..842277a8 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java @@ -2,10 +2,9 @@ package com.genersoft.iot.vmp.service.redisMsg; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; -import com.genersoft.iot.vmp.gb28181.bean.GbStream; +import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.zlm.dto.StreamPush; import com.genersoft.iot.vmp.service.IGbStreamService; -import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.service.IStreamPushService; import com.genersoft.iot.vmp.utils.DateUtil; import org.slf4j.Logger; @@ -60,43 +59,40 @@ public class RedisPushStreamStatusListMsgListener implements MessageListener { List streamPushItems = JSON.parseArray(new String(msg.getBody()), StreamPush.class); //查询全部的app+stream 用于判断是添加还是修改 Map allAppAndStream = streamPushService.getAllAppAndStreamMap(); - Map allGBId = gbStreamService.getAllGBId(); + Map allGBId = streamPushService.getAllGBId(); /** * 用于存储更具APP+Stream过滤后的数据,可以直接存入stream_push表与gb_stream表 */ List streamPushItemForSave = new ArrayList<>(); List streamPushItemForUpdate = new ArrayList<>(); - for (StreamPush streamPushItem : streamPushItems) { - String app = streamPushItem.getApp(); - String stream = streamPushItem.getStream(); + for (StreamPush streamPush : streamPushItems) { + String app = streamPush.getApp(); + String stream = streamPush.getStream(); boolean contains = allAppAndStream.containsKey(app + stream); //不存在就添加 if (!contains) { - if (allGBId.containsKey(streamPushItem.getGbId())) { - GbStream gbStream = allGBId.get(streamPushItem.getGbId()); + if (allGBId.containsKey(streamPush.getGbDeviceId())) { + StreamPush streamPushInDb = allGBId.get(streamPush.getGbDeviceId()); logger.warn("[REDIS消息-推流设备列表更新-INSERT] 国标编号重复: {}, 已分配给{}/{}", - streamPushItem.getGbId(), gbStream.getApp(), gbStream.getStream()); + streamPushInDb.getGbDeviceId(), streamPushInDb.getApp(), streamPushInDb.getStream()); continue; } - streamPushItem.setStreamType("push"); - streamPushItem.setCreateTime(DateUtil.getNow()); - streamPushItem.setMediaServerId(mediaServerService.getDefaultMediaServer().getId()); - streamPushItem.setOriginType(2); - streamPushItem.setOriginTypeStr("rtsp_push"); - streamPushItem.setTotalReaderCount(0); - streamPushItemForSave.add(streamPushItem); - allGBId.put(streamPushItem.getGbId(), streamPushItem); + streamPush.setCreateTime(DateUtil.getNow()); + streamPush.setMediaServerId(mediaServerService.getDefaultMediaServer().getId()); + streamPushItemForSave.add(streamPush); + allGBId.put(streamPush.getGbDeviceId(), streamPush); } else { - if (allGBId.containsKey(streamPushItem.getGbId()) - && (!allGBId.get(streamPushItem.getGbId()).getApp().equals(streamPushItem.getApp()) || !allGBId.get(streamPushItem.getGbId()).getStream().equals(streamPushItem.getStream()))) { - GbStream gbStream = allGBId.get(streamPushItem.getGbId()); + if (allGBId.containsKey(streamPush.getGbDeviceId()) + && (!allGBId.get(streamPush.getGbDeviceId()).getApp().equals(streamPush.getApp()) + || !allGBId.get(streamPush.getGbDeviceId()).getStream().equals(streamPush.getStream()))) { + StreamPush streamPushInDb = allGBId.get(streamPush.getGbDeviceId()); logger.warn("[REDIS消息-推流设备列表更新-UPDATE] 国标编号重复: {}, 已分配给{}/{}", - streamPushItem.getGbId(), gbStream.getApp(), gbStream.getStream()); + streamPush.getGbDeviceId(), streamPushInDb.getApp(), streamPushInDb.getStream()); continue; } //存在就只修改 name和gbId - streamPushItemForUpdate.add(streamPushItem); + streamPushItemForUpdate.add(streamPush); } } if (!streamPushItemForSave.isEmpty()) { diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java index 76da4dc9..383234b3 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.StreamPush; +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; @@ -216,7 +217,7 @@ public interface IRedisCatchStorage { void addPushListItem(String app, String stream, MediaArrivalEvent param); - StreamPush getPushListItem(String app, String stream); + OnStreamChangedHookParam getPushListItem(String app, String stream); void removePushListItem(String app, String stream, String mediaServerId); diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java index a654ea06..af1b4242 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java @@ -53,7 +53,7 @@ public interface CloudRecordServiceMapper { " and id in " + " #{item}" + " " + - " order by start_time DESC" + + " order by start_time ASC" + " ") List getList(@Param("query") String query, @Param("app") String app, @Param("stream") String stream, @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp, diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java index a0746dc5..10372851 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java @@ -87,7 +87,7 @@ public interface StreamPushMapper { List selectAll(); @Select("SELECT st.*, gs.gb_id, gs.name, gs.longitude, gs.latitude FROM wvp_stream_push st LEFT join wvp_gb_stream gs on st.app = gs.app AND st.stream = gs.stream WHERE st.app=#{app} AND st.stream=#{stream}") - StreamPush selectOne(@Param("app") String app, @Param("stream") String stream); + StreamPush selectByAppAndStream(@Param("app") String app, @Param("stream") String stream); @Insert("