Merge branch 'master' into develop-add-api-key
| | |
| | | |
| | | # 非开源的内容 |
| | | - [X] ONVIF设备的接入,支持点播,云台控制,国标级联点播,自动点播。在[知识星球](https://t.zsxq.com/10WAnH2MP)放了试用安装包以及使用教程,没有使用时间限制,需要源码可以星球私信我或者邮箱联系。 |
| | | - [X] 支持国标28181-2022协议,支持巡航轨迹查询,PTZ精准控制,存储卡格式化,设备软件升级,OSD配置,h265+aac,支持辅码流,录像倒放等。具体的功能列表可在[知识星球](https://t.zsxq.com/18GXkpkqs)查看,需要源码和测试可以在星球私信联系或者发邮件给我 |
| | | |
| | | |
| | | # 授权协议 |
| | |
| | | |
| | | # 技术支持 |
| | | |
| | | [知识星球](https://t.zsxq.com/0d8VAD3Dm)专栏列表: |
| | | [知识星球](https://t.zsxq.com/0d8VAD3Dm)专栏列表:, |
| | | - [使用入门系列一:WVP-PRO能做什么](https://t.zsxq.com/0dLguVoSp) |
| | | |
| | | 有偿技术支持,请发送邮件到648540858@qq.com |
| | |
| | | |
| | | import javax.annotation.PostConstruct; |
| | | import java.time.Instant; |
| | | import java.util.Date; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | |
| | | } |
| | | } |
| | | // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔 |
| | | future = threadPoolTaskScheduler.scheduleAtFixedRate(task, cycleForCatalog); |
| | | |
| | | future = threadPoolTaskScheduler.scheduleAtFixedRate(task, new Date(System.currentTimeMillis() + cycleForCatalog), cycleForCatalog); |
| | | if (future != null){ |
| | | futureMap.put(key, future); |
| | | runnableMap.put(key, task); |
| | |
| | | * 云台类型 |
| | | */ |
| | | @Schema(description = "云台类型") |
| | | private int PTZType; |
| | | private int ptzType; |
| | | |
| | | /** |
| | | * 云台类型描述字符串 |
| | | */ |
| | | @Schema(description = "云台类型描述字符串") |
| | | private String PTZTypeText; |
| | | private String ptzTypeText; |
| | | |
| | | /** |
| | | * 创建时间 |
| | |
| | | this.deviceId = deviceId; |
| | | } |
| | | |
| | | public void setPTZType(int PTZType) { |
| | | this.PTZType = PTZType; |
| | | switch (PTZType) { |
| | | public void setPtzType(int ptzType) { |
| | | this.ptzType = ptzType; |
| | | switch (ptzType) { |
| | | case 0: |
| | | this.PTZTypeText = "未知"; |
| | | this.ptzTypeText = "未知"; |
| | | break; |
| | | case 1: |
| | | this.PTZTypeText = "球机"; |
| | | this.ptzTypeText = "球机"; |
| | | break; |
| | | case 2: |
| | | this.PTZTypeText = "半球"; |
| | | this.ptzTypeText = "半球"; |
| | | break; |
| | | case 3: |
| | | this.PTZTypeText = "固定枪机"; |
| | | this.ptzTypeText = "固定枪机"; |
| | | break; |
| | | case 4: |
| | | this.PTZTypeText = "遥控枪机"; |
| | | this.ptzTypeText = "遥控枪机"; |
| | | break; |
| | | } |
| | | } |
| | |
| | | this.password = password; |
| | | } |
| | | |
| | | public int getPTZType() { |
| | | return PTZType; |
| | | public int getPtzType() { |
| | | return ptzType; |
| | | } |
| | | |
| | | public String getPTZTypeText() { |
| | | return PTZTypeText; |
| | | public String getPtzTypeText() { |
| | | return ptzTypeText; |
| | | } |
| | | |
| | | public void setPTZTypeText(String PTZTypeText) { |
| | | this.PTZTypeText = PTZTypeText; |
| | | public void setPtzTypeText(String ptzTypeText) { |
| | | this.ptzTypeText = ptzTypeText; |
| | | } |
| | | |
| | | public boolean isStatus() { |
| | |
| | | return platforms; |
| | | } |
| | | |
| | | public List<String> getAllMobilePositionSubscribePlatform() { |
| | | List<String> platforms = new ArrayList<>(); |
| | | if(!mobilePositionMap.isEmpty()) { |
| | | for (String key : mobilePositionMap.keySet()) { |
| | | platforms.add(mobilePositionMap.get(key).getId()); |
| | | } |
| | | } |
| | | return platforms; |
| | | } |
| | | |
| | | public void removeAllSubscribe(String platformId) { |
| | | removeMobilePositionSubscribe(platformId); |
| | | removeCatalogSubscribe(platformId); |
| | |
| | | import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent; |
| | | import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent; |
| | | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
| | | import com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition.MobilePositionEvent; |
| | | import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent; |
| | | import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | } |
| | | |
| | | |
| | | public void mobilePositionEventPublish(MobilePosition mobilePosition) { |
| | | MobilePositionEvent event = new MobilePositionEvent(this); |
| | | event.setMobilePosition(mobilePosition); |
| | | applicationEventPublisher.publishEvent(event); |
| | | } |
| | | |
| | | |
| | | public void catalogEventPublishForStream(String platformId, List<GbStream> gbStreams, String type) { |
| | | CatalogEvent outEvent = new CatalogEvent(this); |
| | | outEvent.setGbStreams(gbStreams); |
New file |
| | |
| | | package com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition; |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
| | | import org.springframework.context.ApplicationEvent; |
| | | |
| | | public class MobilePositionEvent extends ApplicationEvent { |
| | | public MobilePositionEvent(Object source) { |
| | | super(source); |
| | | } |
| | | |
| | | private MobilePosition mobilePosition; |
| | | |
| | | public MobilePosition getMobilePosition() { |
| | | return mobilePosition; |
| | | } |
| | | |
| | | public void setMobilePosition(MobilePosition mobilePosition) { |
| | | this.mobilePosition = mobilePosition; |
| | | } |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition; |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| | | import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; |
| | | import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
| | | import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; |
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.ApplicationListener; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.sip.InvalidArgumentException; |
| | | import javax.sip.SipException; |
| | | import java.text.ParseException; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 移动位置通知消息转发 |
| | | */ |
| | | @Component |
| | | public class MobilePositionEventLister implements ApplicationListener<MobilePositionEvent> { |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(MobilePositionEventLister.class); |
| | | |
| | | @Autowired |
| | | private IVideoManagerStorage storager; |
| | | |
| | | @Autowired |
| | | private SIPCommanderFroPlatform sipCommanderFroPlatform; |
| | | |
| | | @Autowired |
| | | private SubscribeHolder subscribeHolder; |
| | | |
| | | @Override |
| | | public void onApplicationEvent(MobilePositionEvent event) { |
| | | // 获取所用订阅 |
| | | List<String> platforms = subscribeHolder.getAllMobilePositionSubscribePlatform(); |
| | | if (platforms.isEmpty()) { |
| | | return; |
| | | } |
| | | List<ParentPlatform> parentPlatformsForGB = storager.queryPlatFormListForGBWithGBId(event.getMobilePosition().getChannelId(), platforms); |
| | | |
| | | for (ParentPlatform platform : parentPlatformsForGB) { |
| | | logger.info("[向上级发送MobilePosition] 通道:{},平台:{}, 位置: {}:{}", event.getMobilePosition().getChannelId(), |
| | | platform.getServerGBId(), event.getMobilePosition().getLongitude(), event.getMobilePosition().getLatitude()); |
| | | SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId()); |
| | | try { |
| | | sipCommanderFroPlatform.sendNotifyMobilePosition(platform, GPSMsgInfo.getInstance(event.getMobilePosition()), |
| | | subscribe); |
| | | } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | |
| | | IllegalAccessException e) { |
| | | logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | |
| | |
| | | ssrcTransaction.setType(type); |
| | | |
| | | redisTemplate.opsForValue().set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() |
| | | + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction); |
| | | + ":" + deviceId + ":" + channelId + ":" + callId + ":" + stream, ssrcTransaction); |
| | | } |
| | | |
| | | public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){ |
| | |
| | | if (ObjectUtils.isEmpty(stream)) { |
| | | stream ="*"; |
| | | } |
| | | String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; |
| | | String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":" + deviceId + ":" + channelId + ":" + callId+ ":" + stream; |
| | | List<Object> scanResult = RedisUtil.scan(redisTemplate, key); |
| | | if (scanResult.size() == 0) { |
| | | return null; |
| | |
| | | if (ObjectUtils.isEmpty(callId)) { |
| | | return null; |
| | | } |
| | | String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_" + callId+ "_*"; |
| | | String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":*:*:" + callId+ ":*"; |
| | | List<Object> scanResult = RedisUtil.scan(redisTemplate, key); |
| | | if (!scanResult.isEmpty()) { |
| | | return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); |
| | | }else { |
| | | key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_play_*"; |
| | | key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":*:*:play:*"; |
| | | scanResult = RedisUtil.scan(redisTemplate, key); |
| | | if (scanResult.isEmpty()) { |
| | | return null; |
| | |
| | | if (ObjectUtils.isEmpty(stream)) { |
| | | stream ="*"; |
| | | } |
| | | String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; |
| | | String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":" + deviceId + ":" + channelId + ":" + callId+ ":" + stream; |
| | | List<Object> scanResult = RedisUtil.scan(redisTemplate, key); |
| | | if (scanResult.size() == 0) { |
| | | return null; |
| | |
| | | return; |
| | | } |
| | | for (SsrcTransaction ssrcTransaction : ssrcTransactionList) { |
| | | redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" |
| | | + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream()); |
| | | redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":" |
| | | + deviceId + ":" + channelId + ":" + ssrcTransaction.getCallId() + ":" + ssrcTransaction.getStream()); |
| | | } |
| | | } |
| | | |
| | |
| | | if (ssrcTransaction == null ) { |
| | | return; |
| | | } |
| | | redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" |
| | | + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream()); |
| | | redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":" |
| | | + deviceId + ":" + channelId + ":" + ssrcTransaction.getCallId() + ":" + ssrcTransaction.getStream()); |
| | | } |
| | | |
| | | |
| | |
| | | /** |
| | | * 看守位控制命令 |
| | | * |
| | | * @param device 视频设备 |
| | | * @param channelId 通道id,非通道则是设备本身 |
| | | * @param enabled 看守位使能:1 = 开启,0 = 关闭 |
| | | * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) |
| | | * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 |
| | | */ |
| | | void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; |
| | | void homePositionCmd(Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; |
| | | |
| | | /** |
| | | * 设备配置命令 |
| | |
| | | * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
|
| | | */
|
| | | @Override
|
| | | public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
|
| | | public void homePositionCmd(Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
|
| | |
|
| | | StringBuffer cmdXml = new StringBuffer(200);
|
| | | String charset = device.getCharset();
|
| | |
| | | cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
|
| | | }
|
| | | cmdXml.append("<HomePosition>\r\n");
|
| | | if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {
|
| | | if (enabled) {
|
| | | cmdXml.append("<Enabled>1</Enabled>\r\n");
|
| | | if (NumericUtil.isInteger(resetTime)) {
|
| | | cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
|
| | | } else {
|
| | | cmdXml.append("<ResetTime>0</ResetTime>\r\n");
|
| | | }
|
| | | if (NumericUtil.isInteger(presetIndex)) {
|
| | | cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
|
| | | } else {
|
| | | cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
|
| | | }
|
| | | cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
|
| | | cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
|
| | | } else {
|
| | | cmdXml.append("<Enabled>0</Enabled>\r\n");
|
| | | }
|
| | |
| | | }else { |
| | | catalogXml.append("<Password></Password>\r\n"); |
| | | } |
| | | if (!ObjectUtils.isEmpty(channel.getPTZType())) { |
| | | catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n"); |
| | | if (!ObjectUtils.isEmpty(channel.getPtzType())) { |
| | | catalogXml.append("<PTZType>" + channel.getPtzType() + "</PTZType>\r\n"); |
| | | }else { |
| | | catalogXml.append("<PTZType></PTZType>\r\n"); |
| | | } |
| | |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| | | import com.genersoft.iot.vmp.service.*; |
| | | import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; |
| | | import com.genersoft.iot.vmp.service.bean.RequestStopPushStreamMsg; |
| | | import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| | | import gov.nist.javax.sip.message.SIPRequest; |
| | |
| | | @Autowired |
| | | private UserSetting userSetting; |
| | | |
| | | @Autowired |
| | | private IStreamPushService pushService; |
| | | |
| | | @Autowired |
| | | private RedisGbPlayMsgListener redisGbPlayMsgListener; |
| | | |
| | | @Override |
| | | public void afterPropertiesSet() throws Exception { |
| | | // 添加消息处理的订阅 |
| | |
| | | |
| | | // 收流端发送的停止 |
| | | if (sendRtpItem != null){ |
| | | logger.info("[收到bye] 来自{},停止通道:{}, 类型: {}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), sendRtpItem.getPlayType()); |
| | | logger.info("[收到bye] 来自{},停止通道:{}, 类型: {}, callId: {}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), sendRtpItem.getPlayType(), callIdHeader.getCallId()); |
| | | |
| | | String streamId = sendRtpItem.getStream(); |
| | | Map<String, Object> param = new HashMap<>(); |
| | |
| | | param.put("app",sendRtpItem.getApp()); |
| | | param.put("stream",streamId); |
| | | param.put("ssrc",sendRtpItem.getSsrc()); |
| | | logger.info("[收到bye] 停止推流:{}", streamId); |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), |
| | | callIdHeader.getCallId(), null); |
| | | zlmServerFactory.stopSendRtpStream(mediaInfo, param); |
| | | if (userSetting.getUseCustomSsrcForParentInvite()) { |
| | | mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc()); |
| | | } |
| | | logger.info("[收到bye] 停止推流:{}, 媒体节点: {}", streamId, sendRtpItem.getMediaServerId()); |
| | | |
| | | if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) { |
| | | ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId()); |
| | | if (platform != null) { |
| | | MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, |
| | | sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(), |
| | | sendRtpItem.getPlatformId(), platform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId()); |
| | | messageForPushChannel.setPlatFormIndex(platform.getId()); |
| | | redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel); |
| | | // 查询这路流是否是本平台的 |
| | | StreamPushItem push = pushService.getPush(sendRtpItem.getApp(), sendRtpItem.getStream()); |
| | | if (push!= null && !push.isSelf()) { |
| | | // 不是本平台的就发送redis消息让其他wvp停止发流 |
| | | ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId()); |
| | | if (platform != null) { |
| | | RequestStopPushStreamMsg streamMsg = RequestStopPushStreamMsg.getInstance(sendRtpItem, platform.getName(), platform.getId()); |
| | | redisGbPlayMsgListener.sendMsgForStopSendRtpStream(sendRtpItem.getServerId(), streamMsg); |
| | | } |
| | | }else { |
| | | logger.info("[上级平台停止观看] 未找到平台{}的信息,发送redis消息失败", sendRtpItem.getPlatformId()); |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), |
| | | callIdHeader.getCallId(), null); |
| | | zlmServerFactory.stopSendRtpStream(mediaInfo, param); |
| | | if (userSetting.getUseCustomSsrcForParentInvite()) { |
| | | mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc()); |
| | | } |
| | | |
| | | ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId()); |
| | | if (platform != null) { |
| | | MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, |
| | | sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(), |
| | | sendRtpItem.getPlatformId(), platform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId()); |
| | | messageForPushChannel.setPlatFormIndex(platform.getId()); |
| | | redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel); |
| | | }else { |
| | | logger.info("[上级平台停止观看] 未找到平台{}的信息,发送redis消息失败", sendRtpItem.getPlatformId()); |
| | | } |
| | | } |
| | | }else { |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), |
| | | callIdHeader.getCallId(), null); |
| | | zlmServerFactory.stopSendRtpStream(mediaInfo, param); |
| | | if (userSetting.getUseCustomSsrcForParentInvite()) { |
| | | mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc()); |
| | | } |
| | | } |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | if (mediaInfo != null) { |
| | | AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); |
| | | if (audioBroadcastCatch != null && audioBroadcastCatch.getSipTransactionInfo().getCallId().equals(callIdHeader.getCallId())) { |
| | | // 来自上级平台的停止对讲 |
| | | logger.info("[停止对讲] 来自上级,平台:{}, 通道:{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); |
| | | audioBroadcastManager.del(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); |
| | | } |
| | | |
| | | AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); |
| | | if (audioBroadcastCatch != null && audioBroadcastCatch.getSipTransactionInfo().getCallId().equals(callIdHeader.getCallId())) { |
| | | // 来自上级平台的停止对讲 |
| | | logger.info("[停止对讲] 来自上级,平台:{}, 通道:{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); |
| | | audioBroadcastManager.del(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); |
| | | } |
| | | |
| | | int totalReaderCount = zlmServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId); |
| | | if (totalReaderCount <= 0) { |
| | | logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId); |
| | | if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) { |
| | | Device device = deviceService.getDevice(sendRtpItem.getDeviceId()); |
| | | if (device == null) { |
| | | logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId); |
| | | } |
| | | try { |
| | | logger.info("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); |
| | | cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null); |
| | | } catch (InvalidArgumentException | ParseException | SipException | |
| | | SsrcTransactionNotFoundException e) { |
| | | logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage()); |
| | | int totalReaderCount = zlmServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId); |
| | | if (totalReaderCount <= 0) { |
| | | logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId); |
| | | if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) { |
| | | Device device = deviceService.getDevice(sendRtpItem.getDeviceId()); |
| | | if (device == null) { |
| | | logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId); |
| | | } |
| | | try { |
| | | logger.info("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); |
| | | cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null); |
| | | } catch (InvalidArgumentException | ParseException | SipException | |
| | | SsrcTransactionNotFoundException e) { |
| | | logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 可能是设备发送的停止 |
| | | SsrcTransaction ssrcTransaction = streamSession.getSsrcTransactionByCallId(callIdHeader.getCallId()); |
| | | if (ssrcTransaction == null) { |
| | | return; |
| | | } |
| | | logger.info("[收到bye] 来自设备:{}, 通道已停止推流: {}", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); |
| | | // 可能是设备发送的停止 |
| | | SsrcTransaction ssrcTransaction = streamSession.getSsrcTransactionByCallId(callIdHeader.getCallId()); |
| | | if (ssrcTransaction == null) { |
| | | return; |
| | | } |
| | | logger.info("[收到bye] 来自设备:{}, 通道已停止推流: {}", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); |
| | | |
| | | ParentPlatform platform = platformService.queryPlatformByServerGBId(ssrcTransaction.getDeviceId()); |
| | | if (platform != null ) { |
| | |
| | | String endTimeStr = DateUtil.urlFormatter.format(end); |
| | | String stream = device.getDeviceId() + "_" + channelId + "_" + startTimeStr + "_" + endTimeStr; |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, stream, null, device.isSsrcCheck(), true, 0,false, false, device.getStreamModeForParam()); |
| | | sendRtpItem.setStream(stream); |
| | | // 写入redis, 超时时回复 |
| | | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| | | playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start), |
| | |
| | | Media media = mediaDescription.getMedia(); |
| | | |
| | | Vector mediaFormats = media.getMediaFormats(false); |
| | | if (mediaFormats.contains("8")) { |
| | | // if (mediaFormats.contains("8")) { |
| | | port = media.getMediaPort(); |
| | | String protocol = media.getProtocol(); |
| | | // 区分TCP发流还是udp, 当前默认udp |
| | |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | // } |
| | | } |
| | | if (port == -1) { |
| | | logger.info("不支持的媒体格式,返回415"); |
| | |
| | | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.genersoft.iot.vmp.conf.CivilCodeFileConf; |
| | | import com.genersoft.iot.vmp.conf.SipConfig; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import com.genersoft.iot.vmp.gb28181.bean.*; |
| | |
| | | @Autowired |
| | | private NotifyRequestForCatalogProcessor notifyRequestForCatalogProcessor; |
| | | |
| | | @Autowired |
| | | private CivilCodeFileConf civilCodeFileConf; |
| | | |
| | | private ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>(); |
| | | |
| | | @Qualifier("taskExecutor") |
| | |
| | | @Override |
| | | public void process(RequestEvent evt) { |
| | | try { |
| | | |
| | | if (taskQueue.size() >= userSetting.getMaxNotifyCountQueue()) { |
| | | responseAck((SIPRequest) evt.getRequest(), Response.BUSY_HERE, null, null); |
| | | logger.error("[notify] 待处理消息队列已满 {},返回486 BUSY_HERE,消息不做处理", userSetting.getMaxNotifyCountQueue()); |
| | |
| | | mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); |
| | | mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); |
| | | |
| | | if (userSetting.getSavePositionHistory()) { |
| | | storager.insertMobilePosition(mobilePosition); |
| | | } |
| | | deviceChannelService.updateChannelGPS(device, deviceChannel, mobilePosition); |
| | | |
| | | storager.updateChannelPosition(deviceChannel); |
| | | // 向关联了该通道并且开启移动位置订阅的上级平台发送移动位置订阅消息 |
| | | |
| | | |
| | | // 发送redis消息。 通知位置信息的变化 |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | jsonObject.put("serial", deviceId); |
| | | jsonObject.put("code", channelId); |
| | | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| | | jsonObject.put("latitude", mobilePosition.getLatitude()); |
| | | jsonObject.put("altitude", mobilePosition.getAltitude()); |
| | | jsonObject.put("direction", mobilePosition.getDirection()); |
| | | jsonObject.put("speed", mobilePosition.getSpeed()); |
| | | redisCatchStorage.sendMobilePositionMsg(jsonObject); |
| | | } catch (DocumentException e) { |
| | | logger.error("未处理的异常 ", e); |
| | | } |
| | |
| | | mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); |
| | | mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); |
| | | |
| | | if (userSetting.getSavePositionHistory()) { |
| | | storager.insertMobilePosition(mobilePosition); |
| | | } |
| | | |
| | | storager.updateChannelPosition(deviceChannel); |
| | | // 发送redis消息。 通知位置信息的变化 |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| | | jsonObject.put("code", deviceChannel.getChannelId()); |
| | | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| | | jsonObject.put("latitude", mobilePosition.getLatitude()); |
| | | jsonObject.put("altitude", mobilePosition.getAltitude()); |
| | | jsonObject.put("direction", mobilePosition.getDirection()); |
| | | jsonObject.put("speed", mobilePosition.getSpeed()); |
| | | redisCatchStorage.sendMobilePositionMsg(jsonObject); |
| | | |
| | | deviceChannelService.updateChannelGPS(device, deviceChannel, mobilePosition); |
| | | } |
| | | // TODO: 需要实现存储报警信息、报警分类 |
| | | |
| | | // 回复200 OK |
| | | if (redisCatchStorage.deviceIsOnline(deviceId)) { |
| | |
| | | HomePositionRequest homePosition = loadElement(rootElement, HomePositionRequest.class); |
| | | //获取整个消息主体,我们只需要修改请求头即可 |
| | | HomePositionRequest.HomePosition info = homePosition.getHomePosition(); |
| | | cmder.homePositionCmd(device, channelId, info.getEnabled(), info.getResetTime(), info.getPresetIndex(), |
| | | cmder.homePositionCmd(device, channelId, !"0".equals(info.getEnabled()), Integer.parseInt(info.getResetTime()), Integer.parseInt(info.getPresetIndex()), |
| | | errorResult -> onError(request, errorResult), |
| | | okResult -> onOk(request, okResult)); |
| | | } catch (Exception e) { |
| | |
| | | @Autowired |
| | | private ThreadPoolTaskExecutor taskExecutor; |
| | | |
| | | @Autowired |
| | | private EventPublisher eventPublisher; |
| | | |
| | | |
| | | @Override |
| | | public void afterPropertiesSet() throws Exception { |
| | |
| | | mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); |
| | | mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); |
| | | |
| | | if (userSetting.getSavePositionHistory()) { |
| | | storager.insertMobilePosition(mobilePosition); |
| | | } |
| | | storager.updateChannelPosition(deviceChannel); |
| | | |
| | | // 发送redis消息。 通知位置信息的变化 |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| | | jsonObject.put("code", deviceChannel.getChannelId()); |
| | | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| | | jsonObject.put("latitude", mobilePosition.getLatitude()); |
| | | jsonObject.put("altitude", mobilePosition.getAltitude()); |
| | | jsonObject.put("direction", mobilePosition.getDirection()); |
| | | jsonObject.put("speed", mobilePosition.getSpeed()); |
| | | redisCatchStorage.sendMobilePositionMsg(jsonObject); |
| | | deviceChannelService.updateChannelGPS(device, deviceChannel, mobilePosition); |
| | | } |
| | | } |
| | | if (!ObjectUtils.isEmpty(deviceAlarm.getDeviceId())) { |
| | |
| | | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import com.genersoft.iot.vmp.gb28181.bean.*; |
| | | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; |
| | |
| | | |
| | | @Autowired |
| | | private IDeviceChannelService deviceChannelService; |
| | | |
| | | @Autowired |
| | | private EventPublisher eventPublisher; |
| | | |
| | | private ConcurrentLinkedQueue<SipMsgInfo> taskQueue = new ConcurrentLinkedQueue<>(); |
| | | |
| | |
| | | mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); |
| | | mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); |
| | | |
| | | if (userSetting.getSavePositionHistory()) { |
| | | storager.insertMobilePosition(mobilePosition); |
| | | } |
| | | storager.updateChannelPosition(deviceChannel); |
| | | |
| | | // 发送redis消息。 通知位置信息的变化 |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| | | jsonObject.put("code", deviceChannel.getChannelId()); |
| | | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| | | jsonObject.put("latitude", mobilePosition.getLatitude()); |
| | | jsonObject.put("altitude", mobilePosition.getAltitude()); |
| | | jsonObject.put("direction", mobilePosition.getDirection()); |
| | | jsonObject.put("speed", mobilePosition.getSpeed()); |
| | | redisCatchStorage.sendMobilePositionMsg(jsonObject); |
| | | deviceChannelService.updateChannelGPS(device, deviceChannel, mobilePosition); |
| | | |
| | | } catch (DocumentException e) { |
| | | logger.error("未处理的异常 ", e); |
| | |
| | | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| | |
| | | mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); |
| | | mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); |
| | | |
| | | if (userSetting.getSavePositionHistory()) { |
| | | storager.insertMobilePosition(mobilePosition); |
| | | } |
| | | |
| | | storager.updateChannelPosition(deviceChannel); |
| | | deviceChannelService.updateChannelGPS(device, deviceChannel, mobilePosition); |
| | | |
| | | String key = DeferredResultHolder.CALLBACK_CMD_MOBILE_POSITION + device.getDeviceId(); |
| | | RequestMessage msg = new RequestMessage(); |
| | |
| | | msg.setData(mobilePosition); |
| | | resultHolder.invokeAllResult(msg); |
| | | |
| | | // 发送redis消息。 通知位置信息的变化 |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| | | jsonObject.put("code", deviceChannel.getChannelId()); |
| | | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| | | jsonObject.put("latitude", mobilePosition.getLatitude()); |
| | | jsonObject.put("altitude", mobilePosition.getAltitude()); |
| | | jsonObject.put("direction", mobilePosition.getDirection()); |
| | | jsonObject.put("speed", mobilePosition.getSpeed()); |
| | | redisCatchStorage.sendMobilePositionMsg(jsonObject); |
| | | //回复 200 OK |
| | | try { |
| | | responseAck(request, Response.OK); |
| | |
| | | String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType"); |
| | | if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){ |
| | | try { |
| | | deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo)); |
| | | deviceChannel.setPtzType(Integer.parseInt(ptzTypeFromInfo)); |
| | | }catch (NumberFormatException e){ |
| | | logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo); |
| | | } |
| | | } |
| | | } else { |
| | | try { |
| | | deviceChannel.setPTZType(Integer.parseInt(ptzType)); |
| | | deviceChannel.setPtzType(Integer.parseInt(ptzType)); |
| | | }catch (NumberFormatException e){ |
| | | logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType); |
| | | } |
| | |
| | | private AudioBroadcastManager audioBroadcastManager;
|
| | |
|
| | | @Autowired
|
| | | private ZLMServerFactory zlmServerFactory;
|
| | |
|
| | | @Autowired
|
| | | private IPlayService playService;
|
| | |
|
| | | @Autowired
|
| | |
| | | private VideoStreamSessionManager sessionManager;
|
| | |
|
| | | @Autowired
|
| | | private AssistRESTfulUtils assistRESTfulUtils;
|
| | |
|
| | | @Autowired
|
| | | private SSRCFactory ssrcFactory;
|
| | |
|
| | | @Qualifier("taskExecutor")
|
| | |
| | |
|
| | | taskExecutor.execute(() -> {
|
| | | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
|
| | | if (subscribes != null && subscribes.size() > 0) {
|
| | | if (subscribes != null && !subscribes.isEmpty()) {
|
| | | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
| | | subscribe.response(null, param);
|
| | | }
|
| | |
| | | @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
|
| | | public HookResult onPlay(@RequestBody OnPlayHookParam param) {
|
| | | if (logger.isDebugEnabled()) {
|
| | | logger.debug("[ZLM HOOK] 播放鉴权:{}->{}" + param.getMediaServerId(), param);
|
| | | logger.debug("[ZLM HOOK] 播放鉴权:{}->{}", param.getMediaServerId(), param);
|
| | | }
|
| | | String mediaServerId = param.getMediaServerId();
|
| | |
|
| | |
| | | taskExecutor.execute(() -> {
|
| | | ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);
|
| | | if (subscribe != null) {
|
| | | if (mediaInfo != null) {
|
| | | subscribe.response(mediaInfo, param);
|
| | | } else {
|
| | | new HookResultForOnPublish(1, "zlm not register");
|
| | | }
|
| | | subscribe.response(mediaInfo, param);
|
| | | }
|
| | | });
|
| | |
|
| | |
| | | }
|
| | | // 收到无人观看说明流也没有在往上级推送
|
| | | if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) {
|
| | | List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId(
|
| | | List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChannelId(
|
| | | inviteInfo.getChannelId());
|
| | | if (sendRtpItems.size() > 0) {
|
| | | if (!sendRtpItems.isEmpty()) {
|
| | | for (SendRtpItem sendRtpItem : sendRtpItems) {
|
| | | ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
|
| | | try {
|
| | |
| | | logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId());
|
| | | taskExecutor.execute(() -> {
|
| | | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);
|
| | | if (subscribes != null && subscribes.size() > 0) {
|
| | | if (subscribes != null && !subscribes.isEmpty()) {
|
| | | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
| | | subscribe.response(null, zlmServerConfig);
|
| | | }
|
| | |
| | | */
|
| | | @ResponseBody
|
| | | @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8")
|
| | | public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam
|
| | | public HookResult onRtpServerTimeout(@RequestBody OnRtpServerTimeoutHookParam
|
| | | param) {
|
| | | logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc());
|
| | |
|
| | | taskExecutor.execute(() -> {
|
| | | JSONObject json = (JSONObject) JSON.toJSON(param);
|
| | | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout);
|
| | | if (subscribes != null && !subscribes.isEmpty()) {
|
| | | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
| | |
| | | * 调用zlm RESTful API —— stopSendRtp |
| | | */ |
| | | public Boolean stopSendRtpStream(MediaServerItem mediaServerItem, Map<String, Object>param) { |
| | | if (mediaServerItem == null) { |
| | | logger.error("[停止RTP推流] 失败: 媒体节点为NULL"); |
| | | return false; |
| | | } |
| | | Boolean result = false; |
| | | JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param); |
| | | if (jsonObject == null) { |
| | |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| | | import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
| | | import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; |
| | | import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; |
| | | |
| | |
| | | * 修改通道的码流类型 |
| | | */ |
| | | void updateChannelStreamIdentification(DeviceChannel channel); |
| | | |
| | | List<DeviceChannel> queryChaneListByDeviceId(String deviceId); |
| | | |
| | | void updateChannelGPS(Device device, DeviceChannel deviceChannel, MobilePosition mobilePosition); |
| | | |
| | | } |
| | |
| | | package com.genersoft.iot.vmp.service.bean; |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
| | | import com.genersoft.iot.vmp.utils.DateUtil; |
| | | |
| | | public class GPSMsgInfo { |
| | | |
| | | /** |
| | |
| | | |
| | | private boolean stored; |
| | | |
| | | public static GPSMsgInfo getInstance(MobilePosition mobilePosition) { |
| | | GPSMsgInfo gpsMsgInfo = new GPSMsgInfo(); |
| | | gpsMsgInfo.setId(mobilePosition.getChannelId()); |
| | | gpsMsgInfo.setAltitude(mobilePosition.getAltitude() + ""); |
| | | gpsMsgInfo.setLng(mobilePosition.getLongitude()); |
| | | gpsMsgInfo.setLat(mobilePosition.getLatitude()); |
| | | gpsMsgInfo.setSpeed(mobilePosition.getSpeed()); |
| | | gpsMsgInfo.setDirection(mobilePosition.getDirection() + ""); |
| | | gpsMsgInfo.setTime(DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | return gpsMsgInfo; |
| | | } |
| | | |
| | | |
| | | public String getId() { |
| | | return id; |
New file |
| | |
| | | package com.genersoft.iot.vmp.service.bean; |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; |
| | | |
| | | |
| | | public class RequestStopPushStreamMsg { |
| | | |
| | | |
| | | private SendRtpItem sendRtpItem; |
| | | |
| | | |
| | | private String platformName; |
| | | |
| | | |
| | | private int platFormIndex; |
| | | |
| | | public SendRtpItem getSendRtpItem() { |
| | | return sendRtpItem; |
| | | } |
| | | |
| | | public void setSendRtpItem(SendRtpItem sendRtpItem) { |
| | | this.sendRtpItem = sendRtpItem; |
| | | } |
| | | |
| | | public String getPlatformName() { |
| | | return platformName; |
| | | } |
| | | |
| | | public void setPlatformName(String platformName) { |
| | | this.platformName = platformName; |
| | | } |
| | | |
| | | |
| | | public int getPlatFormIndex() { |
| | | return platFormIndex; |
| | | } |
| | | |
| | | public void setPlatFormIndex(int platFormIndex) { |
| | | this.platFormIndex = platFormIndex; |
| | | } |
| | | |
| | | public static RequestStopPushStreamMsg getInstance(SendRtpItem sendRtpItem, String platformName, int platFormIndex) { |
| | | RequestStopPushStreamMsg streamMsg = new RequestStopPushStreamMsg(); |
| | | streamMsg.setSendRtpItem(sendRtpItem); |
| | | streamMsg.setPlatformName(platformName); |
| | | streamMsg.setPlatFormIndex(platFormIndex); |
| | | return streamMsg; |
| | | } |
| | | } |
| | |
| | | |
| | | public class WvpRedisMsgCmd { |
| | | |
| | | /** |
| | | * 请求获取推流信息 |
| | | */ |
| | | public static final String GET_SEND_ITEM = "GetSendItem"; |
| | | /** |
| | | * 请求推流的请求 |
| | | */ |
| | | public static final String REQUEST_PUSH_STREAM = "RequestPushStream"; |
| | | /** |
| | | * 停止推流的请求 |
| | | */ |
| | | public static final String REQUEST_STOP_PUSH_STREAM = "RequestStopPushStream"; |
| | | |
| | | } |
| | |
| | | package com.genersoft.iot.vmp.service.impl; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.baomidou.dynamic.datasource.annotation.DS; |
| | | import com.genersoft.iot.vmp.common.InviteInfo; |
| | | import com.genersoft.iot.vmp.common.InviteSessionType; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| | | import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
| | | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| | | import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; |
| | | import com.genersoft.iot.vmp.service.IDeviceChannelService; |
| | | import com.genersoft.iot.vmp.service.IInviteStreamService; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; |
| | | import com.genersoft.iot.vmp.storager.dao.DeviceMapper; |
| | | import com.genersoft.iot.vmp.storager.dao.DeviceMobilePositionMapper; |
| | | import com.genersoft.iot.vmp.utils.DateUtil; |
| | | import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; |
| | | import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; |
| | |
| | | private final static Logger logger = LoggerFactory.getLogger(DeviceChannelServiceImpl.class); |
| | | |
| | | @Autowired |
| | | private IRedisCatchStorage redisCatchStorage; |
| | | private EventPublisher eventPublisher; |
| | | |
| | | @Autowired |
| | | private IInviteStreamService inviteStreamService; |
| | |
| | | |
| | | @Autowired |
| | | private DeviceMapper deviceMapper; |
| | | |
| | | @Autowired |
| | | private DeviceMobilePositionMapper deviceMobilePositionMapper; |
| | | |
| | | @Autowired |
| | | private UserSetting userSetting; |
| | | |
| | | @Autowired |
| | | private IRedisCatchStorage redisCatchStorage; |
| | | |
| | | @Override |
| | | public DeviceChannel updateGps(DeviceChannel deviceChannel, Device device) { |
| | |
| | | public void updateChannel(String deviceId, DeviceChannel channel) { |
| | | String channelId = channel.getChannelId(); |
| | | channel.setDeviceId(deviceId); |
| | | // StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); |
| | | InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); |
| | | if (inviteInfo != null && inviteInfo.getStreamInfo() != null) { |
| | | channel.setStreamId(inviteInfo.getStreamInfo().getStream()); |
| | |
| | | } |
| | | channelMapper.updateChannelStreamIdentification(channel); |
| | | } |
| | | |
| | | @Override |
| | | public List<DeviceChannel> queryChaneListByDeviceId(String deviceId) { |
| | | return channelMapper.queryAllChannels(deviceId); |
| | | } |
| | | |
| | | @Override |
| | | public void updateChannelGPS(Device device, DeviceChannel deviceChannel, MobilePosition mobilePosition) { |
| | | if (userSetting.getSavePositionHistory()) { |
| | | deviceMobilePositionMapper.insertNewPosition(mobilePosition); |
| | | } |
| | | |
| | | if (deviceChannel.getChannelId().equals(deviceChannel.getDeviceId())) { |
| | | deviceChannel.setChannelId(null); |
| | | } |
| | | if (deviceChannel.getGpsTime() == null) { |
| | | deviceChannel.setGpsTime(DateUtil.getNow()); |
| | | } |
| | | |
| | | int updated = channelMapper.updatePosition(deviceChannel); |
| | | if (updated == 0) { |
| | | return; |
| | | } |
| | | |
| | | List<DeviceChannel> deviceChannels = new ArrayList<>(); |
| | | if (deviceChannel.getChannelId() == null) { |
| | | // 有的设备这里上报的deviceId与通道Id是一样,这种情况更新设备下的全部通道 |
| | | List<DeviceChannel> deviceChannelsInDb = queryChaneListByDeviceId(device.getDeviceId()); |
| | | deviceChannels.addAll(deviceChannelsInDb); |
| | | }else { |
| | | deviceChannels.add(deviceChannel); |
| | | } |
| | | if (deviceChannels.isEmpty()) { |
| | | return; |
| | | } |
| | | if (deviceChannels.size() > 100) { |
| | | logger.warn("[更新通道位置信息后发送通知] 设备可能是平台,上报的位置信息未标明通道编号," + |
| | | "导致所有通道被更新位置, deviceId:{}", device.getDeviceId()); |
| | | } |
| | | for (DeviceChannel channel : deviceChannels) { |
| | | // 向关联了该通道并且开启移动位置订阅的上级平台发送移动位置订阅消息 |
| | | mobilePosition.setChannelId(channel.getChannelId()); |
| | | try { |
| | | eventPublisher.mobilePositionEventPublish(mobilePosition); |
| | | }catch (Exception e) { |
| | | logger.error("[向上级转发移动位置失败] ", e); |
| | | } |
| | | // 发送redis消息。 通知位置信息的变化 |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); |
| | | jsonObject.put("serial", mobilePosition.getDeviceId()); |
| | | jsonObject.put("code", mobilePosition.getChannelId()); |
| | | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| | | jsonObject.put("latitude", mobilePosition.getLatitude()); |
| | | jsonObject.put("altitude", mobilePosition.getAltitude()); |
| | | jsonObject.put("direction", mobilePosition.getDirection()); |
| | | jsonObject.put("speed", mobilePosition.getSpeed()); |
| | | redisCatchStorage.sendMobilePositionMsg(jsonObject); |
| | | } |
| | | } |
| | | } |
| | |
| | | int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForCatalog(),30); |
| | | // 设置最小值为30 |
| | | dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, (subscribeCycleForCatalog -1) * 1000); |
| | | |
| | | catalogSubscribeTask.run(); |
| | | return true; |
| | | } |
| | | |
| | |
| | | int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForMobilePosition(),30); |
| | | // 刷新订阅 |
| | | dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog * 1000); |
| | | mobilePositionSubscribeTask.run(); |
| | | return true; |
| | | } |
| | | |
| | |
| | | logger.info("调用ZLM推流接口, 结果: {}", jsonObject); |
| | | logger.info("RTP推流成功[ {}/{} ],{}->{}, ", param.get("app"), param.get("stream"), jsonObject.getString("local_port"), |
| | | sendRtpItem.isTcpActive()?"被动发流": param.get("dst_url") + ":" + param.get("dst_port")); |
| | | if (sendRtpItem.getPlayType() == InviteStreamType.PUSH && correlationInfo instanceof ParentPlatform) { |
| | | ParentPlatform platform = (ParentPlatform)correlationInfo; |
| | | MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, sendRtpItem.getApp(), sendRtpItem.getStream(), |
| | | sendRtpItem.getChannelId(), platform.getServerGBId(), platform.getName(), userSetting.getServerId(), |
| | | sendRtpItem.getMediaServerId()); |
| | | messageForPushChannel.setPlatFormIndex(platform.getId()); |
| | | redisCatchStorage.sendPlatformStartPlayMsg(messageForPushChannel); |
| | | } |
| | | } else { |
| | | logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSONObject.toJSONString(param)); |
| | | if (sendRtpItem.isOnlyAudio()) { |
| | |
| | | case WvpRedisMsgCmd.REQUEST_PUSH_STREAM: |
| | | RequestPushStreamMsg param = JSON.to(RequestPushStreamMsg.class, wvpRedisMsg.getContent()); |
| | | requestPushStreamMsgHand(param, wvpRedisMsg.getFromId(), wvpRedisMsg.getSerial()); |
| | | |
| | | break; |
| | | case WvpRedisMsgCmd.REQUEST_STOP_PUSH_STREAM: |
| | | RequestStopPushStreamMsg streamMsg = JSON.to(RequestStopPushStreamMsg.class, wvpRedisMsg.getContent()); |
| | | requestStopPushStreamMsgHand(streamMsg, wvpRedisMsg.getFromId(), wvpRedisMsg.getSerial()); |
| | | break; |
| | | default: |
| | | break; |
| | |
| | | redisTemplate.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject); |
| | | } |
| | | |
| | | /** |
| | | * 发送请求推流的消息 |
| | | */ |
| | | public void sendMsgForStopSendRtpStream(String serverId, RequestStopPushStreamMsg streamMsg) { |
| | | String key = UUID.randomUUID().toString(); |
| | | WvpRedisMsg redisMsg = WvpRedisMsg.getRequestInstance(userSetting.getServerId(), serverId, |
| | | WvpRedisMsgCmd.REQUEST_STOP_PUSH_STREAM, key, JSON.toJSONString(streamMsg)); |
| | | |
| | | JSONObject jsonObject = (JSONObject)JSON.toJSON(redisMsg); |
| | | logger.info("[REDIS 请求其他平台停止推流] {}: {}", serverId, jsonObject); |
| | | redisTemplate.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject); |
| | | } |
| | | |
| | | private SendRtpItem querySendRTPServer(String platformGbId, String channelId, String streamId, String callId) { |
| | | if (platformGbId == null) { |
| | | platformGbId = "*"; |
| | |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 处理收到的请求推流的请求 |
| | | */ |
| | | private void requestStopPushStreamMsgHand(RequestStopPushStreamMsg streamMsg, String fromId, String serial) { |
| | | SendRtpItem sendRtpItem = streamMsg.getSendRtpItem(); |
| | | if (sendRtpItem == null) { |
| | | logger.info("[REDIS 执行其他平台的请求停止推流] 失败: sendRtpItem为NULL"); |
| | | return; |
| | | } |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | if (mediaInfo == null) { |
| | | // TODO 回复错误 |
| | | return; |
| | | } |
| | | Map<String, Object> param = new HashMap<>(); |
| | | param.put("vhost","__defaultVhost__"); |
| | | param.put("app",sendRtpItem.getApp()); |
| | | param.put("stream",sendRtpItem.getStream()); |
| | | param.put("ssrc", sendRtpItem.getSsrc()); |
| | | |
| | | if (zlmServerFactory.stopSendRtpStream(mediaInfo, param)) { |
| | | logger.info("[REDIS 执行其他平台的请求停止推流] 成功: {}/{}", sendRtpItem.getApp(), sendRtpItem.getStream()); |
| | | // 发送redis消息 |
| | | MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, |
| | | sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(), |
| | | sendRtpItem.getPlatformId(), streamMsg.getPlatformName(), userSetting.getServerId(), sendRtpItem.getMediaServerId()); |
| | | messageForPushChannel.setPlatFormIndex(streamMsg.getPlatFormIndex()); |
| | | redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel); |
| | | } |
| | | |
| | | } |
| | | } |
| | |
| | | MessageForPushChannel pushChannel = JSON.parseObject(message.getBody(), MessageForPushChannel.class); |
| | | StreamPushItem push = streamPushService.getPush(pushChannel.getApp(), pushChannel.getStream()); |
| | | if (push != null) { |
| | | List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId( |
| | | List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChannelId( |
| | | push.getGbId()); |
| | | if (!sendRtpItems.isEmpty()) { |
| | | for (SendRtpItem sendRtpItem : sendRtpItems) { |
| | |
| | | streamPushItemForSave.add(streamPushItem); |
| | | allGBId.put(streamPushItem.getGbId(), streamPushItem); |
| | | } else { |
| | | if (allGBId.containsKey(streamPushItem.getGbId())) { |
| | | 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()); |
| | | logger.warn("[REDIS消息-推流设备列表更新-UPDATE] 国标编号重复: {}, 已分配给{}/{}", |
| | | streamPushItem.getGbId(), gbStream.getApp(), gbStream.getStream()); |
| | |
| | | */ |
| | | void sendStreamPushRequestedMsgForStatus(); |
| | | |
| | | List<SendRtpItem> querySendRTPServerByChnnelId(String channelId); |
| | | List<SendRtpItem> querySendRTPServerByChannelId(String channelId); |
| | | |
| | | List<SendRtpItem> querySendRTPServerByStream(String stream); |
| | | |
| | |
| | | "longitude_wgs84, latitude_wgs84, has_audio, create_time, update_time, business_group_id, gps_time, stream_identification) " + |
| | | "VALUES (#{channelId}, #{deviceId}, #{name}, #{manufacture}, #{model}, #{owner}, #{civilCode}, #{block}," + |
| | | "#{address}, #{parental}, #{parentId}, #{safetyWay}, #{registerWay}, #{certNum}, #{certifiable}, #{errCode}, #{secrecy}, " + |
| | | "#{ipAddress}, #{port}, #{password}, #{PTZType}, #{status}, #{streamId}, #{longitude}, #{latitude}, #{longitudeGcj02}, " + |
| | | "#{ipAddress}, #{port}, #{password}, #{ptzType}, #{status}, #{streamId}, #{longitude}, #{latitude}, #{longitudeGcj02}, " + |
| | | "#{latitudeGcj02}, #{longitudeWgs84}, #{latitudeWgs84}, #{hasAudio}, #{createTime}, #{updateTime}, #{businessGroupId}, #{gpsTime}, #{streamIdentification})") |
| | | int add(DeviceChannel channel); |
| | | |
| | |
| | | "<if test='ipAddress != null'>, ip_address=#{ipAddress}</if>" + |
| | | "<if test='port != null'>, port=#{port}</if>" + |
| | | "<if test='password != null'>, password=#{password}</if>" + |
| | | "<if test='PTZType != null'>, custom_ptz_type=#{PTZType}</if>" + |
| | | "<if test='ptzType != null'>, custom_ptz_type=#{ptzType}</if>" + |
| | | "<if test='status != null'>, status=#{status}</if>" + |
| | | "<if test='streamId != null'>, stream_id=#{streamId}</if>" + |
| | | "<if test='hasAudio != null'>, has_audio=#{hasAudio}</if>" + |
| | |
| | | "#{item.owner}, #{item.civilCode}, #{item.block},#{item.subCount}," + |
| | | "#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, " + |
| | | "#{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.secrecy}, " + |
| | | "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " + |
| | | "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.ptzType}, #{item.status}, " + |
| | | "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " + |
| | | "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " + |
| | | "#{item.businessGroupId}, #{item.gpsTime}, #{item.streamIdentification}) " + |
| | |
| | | "#{item.owner}, #{item.civilCode}, #{item.block},#{item.subCount}," + |
| | | "#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, " + |
| | | "#{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.secrecy}, " + |
| | | "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " + |
| | | "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.ptzType}, #{item.status}, " + |
| | | "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " + |
| | | "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " + |
| | | "#{item.businessGroupId}, #{item.gpsTime}) " + |
| | |
| | | "<if test='item.ipAddress != null'>, ip_address=#{item.ipAddress}</if>" + |
| | | "<if test='item.port != null'>, port=#{item.port}</if>" + |
| | | "<if test='item.password != null'>, password=#{item.password}</if>" + |
| | | "<if test='item.PTZType != null'>, ptz_type=#{item.PTZType}</if>" + |
| | | "<if test='item.ptzType != null'>, ptz_type=#{item.ptzType}</if>" + |
| | | "<if test='item.status != null'>, status=#{item.status}</if>" + |
| | | "<if test='item.streamId != null'>, stream_id=#{item.streamId}</if>" + |
| | | "<if test='item.hasAudio != null'>, has_audio=#{item.hasAudio}</if>" + |
| | |
| | | "WHERE device_id=#{deviceId} " + |
| | | " <if test='channelId != null' > AND channel_id=#{channelId}</if>" + |
| | | " </script>"}) |
| | | void updatePosition(DeviceChannel deviceChannel); |
| | | int updatePosition(DeviceChannel deviceChannel); |
| | | |
| | | @Select("SELECT * FROM wvp_device_channel WHERE length(trim(stream_id)) > 0") |
| | | List<DeviceChannel> getAllChannelInPlay(); |
| | |
| | | "charset,"+ |
| | | "ssrc_check,"+ |
| | | "as_message_channel,"+ |
| | | "broadcastPushAfterAck,"+ |
| | | "broadcast_push_after_ack,"+ |
| | | "geo_coord_sys,"+ |
| | | "on_line,"+ |
| | | "media_server_id"+ |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<SendRtpItem> querySendRTPServerByChnnelId(String channelId) { |
| | | public List<SendRtpItem> querySendRTPServerByChannelId(String channelId) { |
| | | if (channelId == null) { |
| | | return null; |
| | | } |
| | |
| | | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| | | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | |
| | | private IVideoManagerStorage storager; |
| | | |
| | | @Autowired |
| | | private SIPCommander cmder; |
| | | private ISIPCommander cmder; |
| | | |
| | | @Autowired |
| | | private DeferredResultHolder resultHolder; |
| | |
| | | @Operation(summary = "看守位控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) |
| | | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| | | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| | | @Parameter(name = "enabled", description = "是否开启看守位 1:开启,0:关闭", required = true) |
| | | @Parameter(name = "enabled", description = "是否开启看守位", required = true) |
| | | @Parameter(name = "presetIndex", description = "调用预置位编号") |
| | | @Parameter(name = "resetTime", description = "自动归位时间间隔") |
| | | @GetMapping("/home_position/{deviceId}/{enabled}") |
| | | public DeferredResult<String> homePositionApi(@PathVariable String deviceId, |
| | | @PathVariable String enabled, |
| | | @RequestParam(required = false) String resetTime, |
| | | @RequestParam(required = false) String presetIndex, |
| | | String channelId) { |
| | | @Parameter(name = "resetTime", description = "自动归位时间间隔 单位:秒") |
| | | @GetMapping("/home_position") |
| | | public DeferredResult<String> homePositionApi(String deviceId, String channelId, Boolean enabled, |
| | | @RequestParam(required = false) Integer resetTime, |
| | | @RequestParam(required = false) Integer presetIndex) { |
| | | if (logger.isDebugEnabled()) { |
| | | logger.debug("报警复位API调用"); |
| | | } |
| | |
| | | device-status-notify: true |
| | | # [可选] 日志配置, 一般不需要改 |
| | | logging: |
| | | config: classpath:logback-spring-local.xml |
| | | config: classpath:logback-spring.xml |
| | | |
| | |
| | | <span v-show="!scope.row.edit">{{ scope.row.location }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="ptztype" label="云台类型" min-width="100"> |
| | | <el-table-column prop="ptzType" label="云台类型" min-width="100"> |
| | | <template v-slot:default="scope"> |
| | | <el-select v-show="scope.row.edit" v-model="scope.row.ptztype" |
| | | <el-select v-show="scope.row.edit" v-model="scope.row.ptzType" |
| | | placeholder="云台类型" filterable> |
| | | <el-option |
| | | v-for="(value, key) in ptzTypes" |
| | |
| | | :value="key" |
| | | /> |
| | | </el-select> |
| | | <div v-show="!scope.row.edit">{{ scope.row.ptztypeText }}</div> |
| | | <div v-show="!scope.row.edit">{{ scope.row.ptzTypeText }}</div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="开启音频" min-width="100"> |
| | |
| | | @click="changeSubchannel(scope.row)">查看 |
| | | </el-button> |
| | | <el-divider v-if="scope.row.subCount > 0 || scope.row.parental === 1" direction="vertical"></el-divider> |
| | | <el-button size="medium" v-bind:disabled="device == null || device.online === 0" |
| | | icon="el-icon-video-camera" |
| | | type="text" @click="queryRecords(scope.row)">设备录像 |
| | | </el-button> |
| | | <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-cloudy" |
| | | type="text" @click="queryCloudRecords(scope.row)">云端录像 |
| | | </el-button> |
| | | <!-- <el-button size="medium" v-bind:disabled="device == null || device.online === 0"--> |
| | | <!-- icon="el-icon-video-camera"--> |
| | | <!-- type="text" @click="queryRecords(scope.row)">设备录像--> |
| | | <!-- </el-button>--> |
| | | <!-- <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-cloudy"--> |
| | | <!-- type="text" @click="queryCloudRecords(scope.row)">云端录像--> |
| | | <!-- </el-button>--> |
| | | <el-dropdown @command="(command)=>{moreClick(command, scope.row)}"> |
| | | <el-button size="medium" type="text" > |
| | | 更多功能<i class="el-icon-arrow-down el-icon--right"></i> |
| | | </el-button> |
| | | <el-dropdown-menu slot="dropdown"> |
| | | <el-dropdown-item command="records" v-bind:disabled="device == null || device.online === 0"> |
| | | 设备录像</el-dropdown-item> |
| | | <el-dropdown-item command="cloudRecords" v-bind:disabled="device == null || device.online === 0" > |
| | | 云端录像</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </el-dropdown> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | that.total = res.data.data.total; |
| | | that.deviceChannelList = res.data.data.list; |
| | | that.deviceChannelList.forEach(e => { |
| | | e.ptztype = e.ptztype + ""; |
| | | e.ptzType = e.ptzType + ""; |
| | | that.$set(e, "edit", false); |
| | | that.$set(e, "location", ""); |
| | | if (e.longitude && e.latitude) { |
| | |
| | | that.isLoging = false; |
| | | // that.$message.error("请求超时"); |
| | | }); |
| | | }, |
| | | moreClick: function (command, itemData) { |
| | | if (command === "records") { |
| | | this.queryRecords(itemData) |
| | | }else if (command === "cloudRecords") { |
| | | this.queryCloudRecords(itemData) |
| | | } |
| | | }, |
| | | queryRecords: function (itemData) { |
| | | let deviceId = this.deviceId; |
| | |
| | | this.total = res.data.data.total; |
| | | this.deviceChannelList = res.data.data.list; |
| | | this.deviceChannelList.forEach(e => { |
| | | e.ptztype = e.ptztype + ""; |
| | | e.ptzType = e.ptzType + ""; |
| | | this.$set(e, "edit", false); |
| | | this.$set(e, "location", ""); |
| | | if (e.longitude && e.latitude) { |
| | |
| | | type = 2; |
| | | } |
| | | console.log(type) |
| | | if (item.basicData.ptztype === 1 ) { // 1-球机;2-半球;3-固定枪机;4-遥控枪机 |
| | | if (item.basicData.ptzType === 1 ) { // 1-球机;2-半球;3-固定枪机;4-遥控枪机 |
| | | type = 4; |
| | | }else if (item.basicData.ptztype === 2) { |
| | | }else if (item.basicData.ptzType === 2) { |
| | | type = 5; |
| | | }else if (item.basicData.ptztype === 3 || item.basicData.ptztype === 4) { |
| | | }else if (item.basicData.ptzType === 3 || item.basicData.ptzType === 4) { |
| | | type = 6; |
| | | } |
| | | }else { |
| | |
| | | <el-descriptions-item label="设备归属" >{{channel.owner}}</el-descriptions-item> |
| | | <el-descriptions-item label="行政区域" >{{channel.civilCode}}</el-descriptions-item> |
| | | <el-descriptions-item label="安装地址" >{{channel.address}}</el-descriptions-item> |
| | | <el-descriptions-item label="云台类型" >{{channel.ptztypeText}}</el-descriptions-item> |
| | | <el-descriptions-item label="云台类型" >{{channel.ptzTypeText}}</el-descriptions-item> |
| | | <el-descriptions-item label="经纬度" >{{channel.longitude}},{{channel.latitude}}</el-descriptions-item> |
| | | <el-descriptions-item label="状态"> |
| | | <el-tag size="small" v-if="channel.status === 1">在线</el-tag> |
| | |
| | | zlmsdpUrl: url,//流地址 |
| | | simulecast: false, |
| | | useCamera: false, |
| | | audioEnable: false, |
| | | videoEnable: false, |
| | | audioEnable: true, |
| | | videoEnable: true, |
| | | recvOnly: true, |
| | | }) |
| | | webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,(e)=>{// ICE 协商出错 |
| | |
| | | }, |
| | | getImageByChannel: function (channel) { |
| | | let src = "static/images/gis/camera.png" |
| | | switch (channel.ptztype) { |
| | | switch (channel.ptzType) { |
| | | case 1: |
| | | if (channel.status === 1) { |
| | | src = "static/images/gis/camera1.png" |