Merge branch 'main' into 级联
# Conflicts:
# src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java
# src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
# src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
# src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
# src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| | |
| | | ### 5.2 编译前端页面 |
| | | ```shell script |
| | | cd wvp-GB28181-pro/web_src/ |
| | | npm --registry=https://registry.npm.taobao.org install |
| | | npm --registry=https://registry.npmmirror.com install |
| | | npm run build |
| | | ``` |
| | | 编译如果报错, 一般都是网络问题, 导致的依赖包下载失败 |
| | |
| | | public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
|
| | | public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_";
|
| | |
|
| | | /**
|
| | | * Redis Const
|
| | | * 设备录像信息结果前缀
|
| | | */
|
| | | public static final String REDIS_RECORD_INFO_RES_PRE = "GB_RECORD_INFO_RES_";
|
| | | /**
|
| | | * Redis Const
|
| | | * 设备录像信息结果前缀
|
| | | */
|
| | | public static final String REDIS_RECORD_INFO_RES_COUNT_PRE = "GB_RECORD_INFO_RES_COUNT:";
|
| | |
|
| | | }
|
| | |
| | | |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.utils.DateUtil; |
| | | import org.junit.jupiter.api.Order; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | |
| | | |
| | | |
| | | @Configuration("mediaConfig") |
| | | @Order(0) |
| | | public class MediaConfig{ |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(MediaConfig.class); |
| | |
| | | import org.apache.http.HttpHost; |
| | | import org.apache.http.HttpRequest; |
| | | import org.apache.http.HttpResponse; |
| | | import org.junit.jupiter.api.Order; |
| | | import org.mitre.dsmiley.httpproxy.ProxyServlet; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | |
| | | */ |
| | | @SuppressWarnings(value = {"rawtypes", "unchecked"}) |
| | | @Configuration |
| | | @Order(1) |
| | | public class ProxyServletConfig { |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(ProxyServletConfig.class); |
| | |
| | | package com.genersoft.iot.vmp.conf; |
| | | |
| | | |
| | | import org.junit.jupiter.api.Order; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.ObjectUtils; |
| | | |
| | | @Component |
| | | @ConfigurationProperties(prefix = "sip", ignoreInvalidFields = true) |
| | | @Order(0) |
| | | public class SipConfig { |
| | | |
| | | private String ip; |
| | |
| | | * @author lin |
| | | */ |
| | | @Component |
| | | @Order(value=3) |
| | | @Order(value=13) |
| | | public class SipPlatformRunner implements CommandLineRunner { |
| | | |
| | | @Autowired |
| | |
| | | package com.genersoft.iot.vmp.conf; |
| | | |
| | | import io.swagger.v3.oas.models.ExternalDocumentation; |
| | | import io.swagger.v3.oas.models.OpenAPI; |
| | | import io.swagger.v3.oas.models.info.Contact; |
| | | import io.swagger.v3.oas.models.info.Info; |
| | | import io.swagger.v3.oas.models.info.License; |
| | | import io.swagger.v3.oas.models.media.StringSchema; |
| | | import io.swagger.v3.oas.models.parameters.HeaderParameter; |
| | | import org.junit.jupiter.api.Order; |
| | | import org.springdoc.core.GroupedOpenApi; |
| | | import org.springdoc.core.SpringDocConfigProperties; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | |
| | | * @author lin |
| | | */ |
| | | @Configuration |
| | | @Order(1) |
| | | public class SpringDocConfig { |
| | | |
| | | @Value("${doc.enabled: true}") |
| | |
| | | package com.genersoft.iot.vmp.conf; |
| | | |
| | | import org.junit.jupiter.api.Order; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.scheduling.annotation.EnableAsync; |
| | |
| | | * @author lin |
| | | */ |
| | | @Configuration |
| | | @Order(1) |
| | | @EnableAsync(proxyTargetClass = true) |
| | | public class ThreadPoolTaskConfig { |
| | | |
| | |
| | | package com.genersoft.iot.vmp.conf; |
| | | |
| | | import org.junit.jupiter.api.Order; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | |
| | | */ |
| | | @Component |
| | | @ConfigurationProperties(prefix = "user-settings", ignoreInvalidFields = true) |
| | | @Order(0) |
| | | public class UserSetting { |
| | | |
| | | private Boolean savePositionHistory = Boolean.FALSE; |
| | |
| | | package com.genersoft.iot.vmp.conf; |
| | | |
| | | import org.junit.jupiter.api.Order; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | @Component |
| | | @ConfigurationProperties(prefix = "version") |
| | | @Order(0) |
| | | public class VersionConfig { |
| | | |
| | | private String version; |
| | |
| | | |
| | | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| | | import com.genersoft.iot.vmp.service.redisMsg.*; |
| | | import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.cache.annotation.CachingConfigurerSupport; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.core.annotation.Order; |
| | | import org.springframework.data.redis.connection.RedisConnectionFactory; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | | import org.springframework.data.redis.listener.PatternTopic; |
| | | import org.springframework.data.redis.listener.RedisMessageListenerContainer; |
| | | import org.springframework.data.redis.serializer.StringRedisSerializer; |
| | | |
| | | import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer; |
| | | |
| | | |
| | | /** |
| | |
| | | * |
| | | */ |
| | | @Configuration |
| | | @Order(value=1) |
| | | public class RedisConfig extends CachingConfigurerSupport { |
| | | |
| | | @Autowired |
| | |
| | | package com.genersoft.iot.vmp.conf.security; |
| | | |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import org.junit.jupiter.api.Order; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | @Configuration |
| | | @EnableWebSecurity |
| | | @EnableGlobalMethodSecurity(prePostEnabled = true) |
| | | @Order(1) |
| | | public class WebSecurityConfig extends WebSecurityConfigurerAdapter { |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class); |
| | |
| | | import java.util.concurrent.ConcurrentHashMap;
|
| | |
|
| | | @Component
|
| | | @Order(value=1)
|
| | | @Order(value=10)
|
| | | public class SipLayer implements CommandLineRunner {
|
| | |
|
| | | private final static Logger logger = LoggerFactory.getLogger(SipLayer.class);
|
| | |
| | | return sipTransactionInfo; |
| | | } |
| | | |
| | | public MediaServerItem getMediaServerItem() { |
| | | return mediaServerItem; |
| | | } |
| | | |
| | | public void setMediaServerItem(MediaServerItem mediaServerItem) { |
| | | this.mediaServerItem = mediaServerItem; |
| | | } |
| | | |
| | | public String getApp() { |
| | | return app; |
| | | } |
| | | |
| | | public void setApp(String app) { |
| | | this.app = app; |
| | | } |
| | | |
| | | public String getStream() { |
| | | return stream; |
| | | } |
| | | |
| | | public void setStream(String stream) { |
| | | this.stream = stream; |
| | | } |
| | | |
| | | public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) { |
| | | this.sipTransactionInfo = sipTransactionInfo; |
| | | } |
| | |
| | | * @author lin |
| | | */ |
| | | @Component |
| | | @Order(value=4) |
| | | @Order(value=14) |
| | | public class SipRunner implements CommandLineRunner { |
| | | |
| | | @Autowired |
| | |
| | | // 重置cseq计数 |
| | | redisCatchStorage.resetAllCSEQ(); |
| | | // 清理redis |
| | | // 清理数据库不存在但是redis中存在的数据 |
| | | List<Device> devicesInDb = deviceService.getAll(); |
| | | if (devicesInDb.size() == 0) { |
| | | redisCatchStorage.removeAllDevice(); |
| | | }else { |
| | | List<Device> devicesInRedis = redisCatchStorage.getAllDevices(); |
| | | if (devicesInRedis.size() > 0) { |
| | | Map<String, Device> deviceMapInDb = new HashMap<>(); |
| | | devicesInDb.parallelStream().forEach(device -> { |
| | | deviceMapInDb.put(device.getDeviceId(), device); |
| | | }); |
| | | devicesInRedis.parallelStream().forEach(device -> { |
| | | if (deviceMapInDb.get(device.getDeviceId()) == null) { |
| | | redisCatchStorage.removeDevice(device.getDeviceId()); |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | |
| | | |
| | | // 查找国标推流 |
| | | List<SendRtpItem> sendRtpItems = redisCatchStorage.queryAllSendRTPServer(); |
| | | if (sendRtpItems.size() > 0) { |
| | |
| | | }else { |
| | | catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n"); |
| | | } |
| | | catalogXml.append("<Block>" + channel.getBlock() + "</Block>\r\n"); |
| | | catalogXml.append("<SafetyWay>" + channel.getSafetyWay() + "</SafetyWay>\r\n"); |
| | | catalogXml.append("<CertNum>" + channel.getCertNum() + "</CertNum>\r\n"); |
| | | catalogXml.append("<Certifiable>" + channel.getCertifiable() + "</Certifiable>\r\n"); |
| | | catalogXml.append("<ErrCode>" + channel.getErrCode() + "</ErrCode>\r\n"); |
| | | catalogXml.append("<EndTime>" + channel.getEndTime() + "</EndTime>\r\n"); |
| | | catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); |
| | | catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n"); |
| | | catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n"); |
| | | catalogXml.append("<Password>" + channel.getPort() + "</Password>\r\n"); |
| | | catalogXml.append("<Status>" + (channel.getStatus() == 1?"ON":"OFF") + "</Status>\r\n"); |
| | | catalogXml.append("<Longitude>" + |
| | | (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude()) |
| | | + "</Longitude>\r\n"); |
| | | catalogXml.append("<Latitude>" + |
| | | (channel.getLatitudeWgs84() != 0? channel.getLatitudeWgs84():channel.getLatitude()) |
| | | + "</Latitude>\r\n"); |
| | | |
| | | |
| | | } |
| | | } |
| | | catalogXml.append("</Item>\r\n"); |
| | |
| | | return; |
| | | } |
| | | String username = sdp.getOrigin().getUsername(); |
| | | String addressStr = sdp.getOrigin().getAddress(); |
| | | String addressStr = sdp.getConnection().getAddress(); |
| | | |
| | | logger.info("[上级点播]用户:{}, 通道:{}, 地址:{}:{}, ssrc:{}", username, channelId, addressStr, port, ssrc); |
| | | Device device = null; |
| | |
| | | |
| | | // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备) |
| | | Device device = redisCatchStorage.getDevice(requesterId); |
| | | AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(requesterId, channelId); |
| | | if (audioBroadcastCatch == null) { |
| | | AudioBroadcastCatch broadcastCatch = audioBroadcastManager.get(requesterId, channelId); |
| | | if (broadcastCatch == null) { |
| | | logger.warn("来自设备的Invite请求非语音广播,已忽略,requesterId: {}/{}", requesterId, channelId); |
| | | try { |
| | | responseAck(request, Response.FORBIDDEN); |
| | |
| | | } |
| | | if (device != null) { |
| | | logger.info("收到设备" + requesterId + "的语音广播Invite请求"); |
| | | String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + device.getDeviceId() + audioBroadcastCatch.getChannelId(); |
| | | String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + device.getDeviceId() + broadcastCatch.getChannelId(); |
| | | dynamicTask.stop(key); |
| | | try { |
| | | responseAck(request, Response.TRYING); |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId()); |
| | | return; |
| | | } |
| | | String contentString = new String(request.getRawContent()); |
| | |
| | | responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] invite 不支持的媒体格式: {}", e.getMessage()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId()); |
| | | return; |
| | | } |
| | | return; |
| | | } |
| | | String addressStr = sdp.getOrigin().getAddress(); |
| | | String addressStr = sdp.getConnection().getAddress(); |
| | | logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, ssrc, |
| | | mediaTransmissionTCP ? (tcpActive? "TCP主动":"TCP被动") : "UDP"); |
| | | |
| | | MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device); |
| | | if (mediaServerItem == null) { |
| | | logger.warn("未找到可用的zlm"); |
| | | try { |
| | | responseAck(request, Response.BUSY_HERE); |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] invite 未找到可用的zlm: {}", e.getMessage()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); |
| | | } |
| | | return; |
| | | } |
| | | MediaServerItem mediaServerItem = broadcastCatch.getMediaServerItem(); |
| | | SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, |
| | | device.getDeviceId(), audioBroadcastCatch.getChannelId(), |
| | | device.getDeviceId(), broadcastCatch.getChannelId(), |
| | | mediaTransmissionTCP, false); |
| | | |
| | | if (sendRtpItem == null) { |
| | |
| | | responseAck(request, Response.BUSY_HERE); |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId()); |
| | | return; |
| | | } |
| | | return; |
| | | } |
| | | |
| | | String app = "broadcast"; |
| | | String stream = device.getDeviceId() + "_" + audioBroadcastCatch.getChannelId(); |
| | | |
| | | CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); |
| | | sendRtpItem.setPlayType(InviteStreamType.BROADCAST); |
| | | sendRtpItem.setCallId(callIdHeader.getCallId()); |
| | | sendRtpItem.setPlatformId(requesterId); |
| | | sendRtpItem.setStatus(1); |
| | | sendRtpItem.setApp(app); |
| | | sendRtpItem.setStreamId(stream); |
| | | sendRtpItem.setApp(broadcastCatch.getApp()); |
| | | sendRtpItem.setStreamId(broadcastCatch.getStream()); |
| | | sendRtpItem.setPt(8); |
| | | sendRtpItem.setUsePs(false); |
| | | sendRtpItem.setRtcp(false); |
| | |
| | | |
| | | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| | | |
| | | |
| | | Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream); |
| | | Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream()); |
| | | if (streamReady) { |
| | | sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, ssrc); |
| | | }else { |
| | | logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", app, stream); |
| | | logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", broadcastCatch.getApp(), broadcastCatch.getStream()); |
| | | try { |
| | | responseAck(request, Response.GONE); |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] 语音通话 回复410失败, {}", e.getMessage()); |
| | | return; |
| | | } |
| | | playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId()); |
| | | } |
| | | } catch (SdpException e) { |
| | | logger.error("[SDP解析异常]", e); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId()); |
| | | } |
| | | } else { |
| | | logger.warn("来自无效设备/平台的请求"); |
| | |
| | | import javax.sip.message.Response; |
| | | import java.text.ParseException; |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | import java.util.concurrent.ConcurrentLinkedQueue; |
| | | |
| | | /** |
| | |
| | | Element deviceIdElement = rootElement.element("DeviceID"); |
| | | String channelId = deviceIdElement.getTextTrim().toString(); |
| | | Device device = redisCatchStorage.getDevice(deviceId); |
| | | |
| | | if (device == null) { |
| | | // 根据通道id查询设备Id |
| | | List<Device> deviceList = deviceChannelService.getDeviceByChannelId(channelId); |
| | | if (deviceList.size() > 0) { |
| | | device = deviceList.get(0); |
| | | }else { |
| | | logger.warn("[mobilePosition移动位置Notify] 未找到通道{}所属的设备", channelId); |
| | | return; |
| | | } |
| | | } |
| | | if (device != null) { |
| | | if (!ObjectUtils.isEmpty(device.getName())) { |
| | | mobilePosition.setDeviceName(device.getName()); |
| | |
| | | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; |
| | | |
| | | import com.genersoft.iot.vmp.conf.ServiceInfo; |
| | | import com.genersoft.iot.vmp.conf.SipConfig; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper; |
| | |
| | | // } |
| | | // } |
| | | |
| | | System.out.println(ServiceInfo.getServerPort()); |
| | | // System.out.println(ServiceInfo.getServerPort()); |
| | | SIPRequest request = (SIPRequest)evt.getRequest(); |
| | | Response response = null; |
| | | boolean passwordCorrect = false; |
| | |
| | | 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.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; |
| | |
| | | continue; |
| | | } |
| | | DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device, null); |
| | | deviceChannel = SipUtils.updateGps(deviceChannel, device.getGeoCoordSys()); |
| | | deviceChannel.setDeviceId(take.getDevice().getDeviceId()); |
| | | |
| | | channelList.add(deviceChannel); |
| | |
| | | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; |
| | | |
| | | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| | | import com.genersoft.iot.vmp.gb28181.bean.*; |
| | | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| | | import com.genersoft.iot.vmp.gb28181.session.RecordDataCatch; |
| | | 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.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.response.ResponseMessageHandler; |
| | | import com.genersoft.iot.vmp.utils.DateUtil; |
| | | import com.genersoft.iot.vmp.utils.UJson; |
| | | import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
| | | import gov.nist.javax.sip.message.SIPRequest; |
| | | import org.dom4j.DocumentException; |
| | | import org.dom4j.Element; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | |
| | | import javax.sip.SipException; |
| | | import javax.sip.message.Response; |
| | | import java.text.ParseException; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | import java.util.*; |
| | | import java.util.concurrent.ConcurrentLinkedQueue; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; |
| | | |
| | |
| | | private ResponseMessageHandler responseMessageHandler; |
| | | |
| | | @Autowired |
| | | private RecordDataCatch recordDataCatch; |
| | | |
| | | @Autowired |
| | | private DeferredResultHolder deferredResultHolder; |
| | | |
| | | @Autowired |
| | |
| | | @Autowired |
| | | private ThreadPoolTaskExecutor taskExecutor; |
| | | |
| | | private Long recordInfoTtl = 1800L; |
| | | |
| | | @Override |
| | | public void afterPropertiesSet() throws Exception { |
| | | responseMessageHandler.addHandler(cmdType, this); |
| | |
| | | |
| | | @Override |
| | | public void handForDevice(RequestEvent evt, Device device, Element rootElement) { |
| | | boolean isEmpty = taskQueue.isEmpty(); |
| | | try { |
| | | // 回复200 OK |
| | | responseAck((SIPRequest) evt.getRequest(), Response.OK); |
| | | }catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] 国标级联 国标录像: {}", e.getMessage()); |
| | | } |
| | | taskQueue.offer(new HandlerCatchData(evt, device, rootElement)); |
| | | if (isEmpty) { |
| | | taskExecutor.execute(()->{ |
| | | while (!taskQueue.isEmpty()) { |
| | | try { |
| | | HandlerCatchData take = taskQueue.poll(); |
| | | Element rootElementForCharset = getRootElement(take.getEvt(), take.getDevice().getCharset()); |
| | | if (rootElement == null) { |
| | | logger.warn("[ 国标录像 ] content cannot be null, {}", evt.getRequest()); |
| | | continue; |
| | | } |
| | | String sn = getText(rootElementForCharset, "SN"); |
| | | String channelId = getText(rootElementForCharset, "DeviceID"); |
| | | RecordInfo recordInfo = new RecordInfo(); |
| | | recordInfo.setChannelId(channelId); |
| | | recordInfo.setDeviceId(take.getDevice().getDeviceId()); |
| | | recordInfo.setSn(sn); |
| | | recordInfo.setName(getText(rootElementForCharset, "Name")); |
| | | String sumNumStr = getText(rootElementForCharset, "SumNum"); |
| | | int sumNum = 0; |
| | | if (!ObjectUtils.isEmpty(sumNumStr)) { |
| | | sumNum = Integer.parseInt(sumNumStr); |
| | | } |
| | | recordInfo.setSumNum(sumNum); |
| | | Element recordListElement = rootElementForCharset.element("RecordList"); |
| | | if (recordListElement == null || sumNum == 0) { |
| | | logger.info("无录像数据"); |
| | | int count = recordDataCatch.put(take.getDevice().getDeviceId(),channelId, sn, sumNum, new ArrayList<>()); |
| | | recordInfo.setCount(count); |
| | | eventPublisher.recordEndEventPush(recordInfo); |
| | | releaseRequest(take.getDevice().getDeviceId(), sn); |
| | | } else { |
| | | Iterator<Element> recordListIterator = recordListElement.elementIterator(); |
| | | if (recordListIterator != null) { |
| | | List<RecordItem> recordList = new ArrayList<>(); |
| | | // 遍历DeviceList |
| | | while (recordListIterator.hasNext()) { |
| | | Element itemRecord = recordListIterator.next(); |
| | | Element recordElement = itemRecord.element("DeviceID"); |
| | | if (recordElement == null) { |
| | | logger.info("记录为空,下一个..."); |
| | | continue; |
| | | } |
| | | RecordItem record = new RecordItem(); |
| | | record.setDeviceId(getText(itemRecord, "DeviceID")); |
| | | record.setName(getText(itemRecord, "Name")); |
| | | record.setFilePath(getText(itemRecord, "FilePath")); |
| | | record.setFileSize(getText(itemRecord, "FileSize")); |
| | | record.setAddress(getText(itemRecord, "Address")); |
| | | taskExecutor.execute(()->{ |
| | | try { |
| | | |
| | | String startTimeStr = getText(itemRecord, "StartTime"); |
| | | record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTimeStr)); |
| | | |
| | | String endTimeStr = getText(itemRecord, "EndTime"); |
| | | record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTimeStr)); |
| | | |
| | | record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 |
| | | : Integer.parseInt(getText(itemRecord, "Secrecy"))); |
| | | record.setType(getText(itemRecord, "Type")); |
| | | record.setRecorderId(getText(itemRecord, "RecorderID")); |
| | | recordList.add(record); |
| | | } |
| | | recordInfo.setRecordList(recordList); |
| | | int count = recordDataCatch.put(take.getDevice().getDeviceId(),channelId, sn, sumNum, recordList);recordInfo.setCount(count); |
| | | logger.info("[国标录像], {}->{}: {}/{}", take.getDevice().getDeviceId(), sn, count, sumNum); |
| | | // 发送消息,如果是上级查询此录像,则会通过这里通知给上级 |
| | | eventPublisher.recordEndEventPush(recordInfo); |
| | | String sn = getText(rootElement, "SN"); |
| | | String channelId = getText(rootElement, "DeviceID"); |
| | | RecordInfo recordInfo = new RecordInfo(); |
| | | recordInfo.setChannelId(channelId); |
| | | recordInfo.setDeviceId(device.getDeviceId()); |
| | | recordInfo.setSn(sn); |
| | | recordInfo.setName(getText(rootElement, "Name")); |
| | | String sumNumStr = getText(rootElement, "SumNum"); |
| | | int sumNum = 0; |
| | | if (!ObjectUtils.isEmpty(sumNumStr)) { |
| | | sumNum = Integer.parseInt(sumNumStr); |
| | | } |
| | | recordInfo.setSumNum(sumNum); |
| | | Element recordListElement = rootElement.element("RecordList"); |
| | | if (recordListElement == null || sumNum == 0) { |
| | | logger.info("无录像数据"); |
| | | recordInfo.setCount(sumNum); |
| | | eventPublisher.recordEndEventPush(recordInfo); |
| | | releaseRequest(device.getDeviceId(), sn,recordInfo); |
| | | } else { |
| | | Iterator<Element> recordListIterator = recordListElement.elementIterator(); |
| | | if (recordListIterator != null) { |
| | | List<RecordItem> recordList = new ArrayList<>(); |
| | | // 遍历DeviceList |
| | | while (recordListIterator.hasNext()) { |
| | | Element itemRecord = recordListIterator.next(); |
| | | Element recordElement = itemRecord.element("DeviceID"); |
| | | if (recordElement == null) { |
| | | logger.info("记录为空,下一个..."); |
| | | continue; |
| | | } |
| | | if (recordDataCatch.isComplete(take.getDevice().getDeviceId(), sn)){ |
| | | releaseRequest(take.getDevice().getDeviceId(), sn); |
| | | } |
| | | RecordItem record = new RecordItem(); |
| | | record.setDeviceId(getText(itemRecord, "DeviceID")); |
| | | record.setName(getText(itemRecord, "Name")); |
| | | record.setFilePath(getText(itemRecord, "FilePath")); |
| | | record.setFileSize(getText(itemRecord, "FileSize")); |
| | | record.setAddress(getText(itemRecord, "Address")); |
| | | |
| | | String startTimeStr = getText(itemRecord, "StartTime"); |
| | | record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTimeStr)); |
| | | |
| | | String endTimeStr = getText(itemRecord, "EndTime"); |
| | | record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTimeStr)); |
| | | |
| | | record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 |
| | | : Integer.parseInt(getText(itemRecord, "Secrecy"))); |
| | | record.setType(getText(itemRecord, "Type")); |
| | | record.setRecorderId(getText(itemRecord, "RecorderID")); |
| | | recordList.add(record); |
| | | } |
| | | } catch (DocumentException e) { |
| | | logger.error("xml解析异常: ", e); |
| | | } catch (Exception e) { |
| | | logger.warn("[国标录像] 发现未处理的异常, {}\r\n{}",e.getMessage(), evt.getRequest()); |
| | | Map<String, String> map = recordList.stream() |
| | | .filter(record -> record.getDeviceId() != null) |
| | | .collect(Collectors.toMap(record -> record.getStartTime()+ record.getEndTime(), UJson::writeJson)); |
| | | // 获取任务结果数据 |
| | | String resKey = VideoManagerConstants.REDIS_RECORD_INFO_RES_PRE + channelId + sn; |
| | | RedisUtil.hmset(resKey, map, recordInfoTtl); |
| | | String resCountKey = VideoManagerConstants.REDIS_RECORD_INFO_RES_COUNT_PRE + channelId + sn; |
| | | long incr = RedisUtil.incr(resCountKey, map.size()); |
| | | RedisUtil.expire(resCountKey, recordInfoTtl); |
| | | recordInfo.setRecordList(recordList); |
| | | recordInfo.setCount(Math.toIntExact(incr)); |
| | | eventPublisher.recordEndEventPush(recordInfo); |
| | | if (incr < sumNum) { |
| | | return; |
| | | } |
| | | // 已接收完成 |
| | | List<RecordItem> resList = RedisUtil.hmget(resKey).values().stream().map(e -> UJson.readJson(e.toString(), RecordItem.class)).collect(Collectors.toList()); |
| | | if (resList.size() < sumNum) { |
| | | return; |
| | | } |
| | | recordInfo.setRecordList(resList); |
| | | releaseRequest(device.getDeviceId(), sn,recordInfo); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | } catch (Exception e) { |
| | | logger.error("[国标录像] 发现未处理的异常, "+e.getMessage(), e); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | } |
| | | |
| | | public void releaseRequest(String deviceId, String sn){ |
| | | public void releaseRequest(String deviceId, String sn,RecordInfo recordInfo){ |
| | | String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn; |
| | | // 对数据进行排序 |
| | | Collections.sort(recordDataCatch.getRecordInfo(deviceId, sn).getRecordList()); |
| | | Collections.sort(recordInfo.getRecordList()); |
| | | |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setKey(key); |
| | | msg.setData(recordDataCatch.getRecordInfo(deviceId, sn)); |
| | | msg.setData(recordInfo); |
| | | deferredResultHolder.invokeAllResult(msg); |
| | | recordDataCatch.remove(deviceId, sn); |
| | | } |
| | | } |
| | |
| | | */ |
| | | @Override |
| | | public void process(ResponseEvent evt ){ |
| | | logger.debug("接收到消息:" + evt.getResponse()); |
| | | try { |
| | | |
| | | SIPResponse response = (SIPResponse)evt.getResponse(); |
| | | int statusCode = response.getStatusCode(); |
| | | // trying不会回复 |
| | |
| | | package com.genersoft.iot.vmp.gb28181.utils; |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| | | import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; |
| | | import com.genersoft.iot.vmp.utils.GitUtil; |
| | | import gov.nist.javax.sip.address.AddressImpl; |
| | |
| | | |
| | | return new RemoteAddressInfo(remoteAddress, remotePort); |
| | | } |
| | | |
| | | public static DeviceChannel updateGps(DeviceChannel deviceChannel, String geoCoordSys) { |
| | | if (deviceChannel.getLongitude()*deviceChannel.getLatitude() > 0) { |
| | | |
| | | if (geoCoordSys == null) { |
| | | geoCoordSys = "WGS84"; |
| | | } |
| | | if ("WGS84".equals(geoCoordSys)) { |
| | | deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude()); |
| | | deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude()); |
| | | Double[] position = Coordtransform.WGS84ToGCJ02(deviceChannel.getLongitude(), deviceChannel.getLatitude()); |
| | | deviceChannel.setLongitudeGcj02(position[0]); |
| | | deviceChannel.setLatitudeGcj02(position[1]); |
| | | }else if ("GCJ02".equals(geoCoordSys)) { |
| | | deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude()); |
| | | deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude()); |
| | | Double[] position = Coordtransform.GCJ02ToWGS84(deviceChannel.getLongitude(), deviceChannel.getLatitude()); |
| | | deviceChannel.setLongitudeWgs84(position[0]); |
| | | deviceChannel.setLatitudeWgs84(position[1]); |
| | | }else { |
| | | deviceChannel.setLongitudeGcj02(0.00); |
| | | deviceChannel.setLatitudeGcj02(0.00); |
| | | deviceChannel.setLongitudeWgs84(0.00); |
| | | deviceChannel.setLatitudeWgs84(0.00); |
| | | } |
| | | }else { |
| | | deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude()); |
| | | deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude()); |
| | | deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude()); |
| | | deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude()); |
| | | } |
| | | return deviceChannel; |
| | | } |
| | | } |
| | |
| | | package com.genersoft.iot.vmp.gb28181.utils;
|
| | |
|
| | | import com.alibaba.fastjson2.JSON;
|
| | | import com.alibaba.fastjson2.JSONArray;
|
| | | import com.alibaba.fastjson2.JSONObject;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.Device;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.TreeType;
|
| | | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
|
| | | import com.genersoft.iot.vmp.utils.DateUtil;
|
| | | import org.dom4j.Attribute;
|
| | |
| | | } else {
|
| | | deviceChannel.setLatitude(0.00);
|
| | | }
|
| | |
|
| | | deviceChannel.setGpsTime(DateUtil.getNow());
|
| | |
|
| | |
|
| | |
| | | } else {
|
| | | deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
|
| | | }
|
| | |
|
| | | return deviceChannel;
|
| | | }
|
| | |
|
| | |
| | | taskExecutor.execute(() -> {
|
| | | ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);
|
| | | if (subscribe != null) {
|
| | |
|
| | | if (mediaInfo != null) {
|
| | | subscribe.response(mediaInfo, json);
|
| | | }
|
| | | }
|
| | | // 流消失移除redis play
|
| | | List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
|
| | | if (param.isRegist()) {
|
| | | if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
|
| | | || param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
|
| | |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | @Component |
| | | @Order(value=2) |
| | | @Order(value=12) |
| | | public class ZLMRunner implements CommandLineRunner { |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(ZLMRunner.class); |
| | |
| | | * @return |
| | | */ |
| | | List<ChannelReduce> queryAllChannelList(String platformId); |
| | | |
| | | /** |
| | | * 数据位置信息格式处理 |
| | | */ |
| | | boolean updateAllGps(Device device); |
| | | |
| | | /** |
| | | * 查询通道所属的设备 |
| | | */ |
| | | List<Device> getDeviceByChannelId(String channelId); |
| | | } |
| | |
| | | */ |
| | | ResourceBaceInfo getOverview(); |
| | | |
| | | /** |
| | | * 获取所有设备 |
| | | */ |
| | | List<Device> getAll(); |
| | | } |
| | |
| | | |
| | | void stopAudioBroadcast(String deviceId, String channelId); |
| | | |
| | | void audioBroadcastCmd(Device device, String channelId, int timeout, MediaServerItem mediaServerItem, String sourceApp, String sourceStream, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException; |
| | | |
| | | void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException; |
| | | |
| | | void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException; |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.concurrent.CopyOnWriteArrayList; |
| | | |
| | | /** |
| | | * @author lin |
| | |
| | | return channelMapper.queryChannelListInAll(null, null, null, platformId, null); |
| | | } |
| | | |
| | | @Override |
| | | public boolean updateAllGps(Device device) { |
| | | List<DeviceChannel> deviceChannels = channelMapper.getChannelsWithoutTransform(device.getDeviceId()); |
| | | List<DeviceChannel> result = new CopyOnWriteArrayList<>(); |
| | | if (deviceChannels.size() == 0) { |
| | | return true; |
| | | } |
| | | String now = DateUtil.getNow(); |
| | | deviceChannels.parallelStream().forEach(deviceChannel -> { |
| | | deviceChannel.setUpdateTime(now); |
| | | result.add(updateGps(deviceChannel, device)); |
| | | }); |
| | | int limitCount = 300; |
| | | if (result.size() > limitCount) { |
| | | for (int i = 0; i < result.size(); i += limitCount) { |
| | | int toIndex = i + limitCount; |
| | | if (i + limitCount > result.size()) { |
| | | toIndex = result.size(); |
| | | } |
| | | channelMapper.batchUpdate(result.subList(i, toIndex)); |
| | | } |
| | | }else { |
| | | channelMapper.batchUpdate(result); |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public List<Device> getDeviceByChannelId(String channelId) { |
| | | return channelMapper.getDeviceByChannelId(channelId); |
| | | } |
| | | } |
| | |
| | | public ResourceBaceInfo getOverview() { |
| | | return deviceMapper.getOverview(); |
| | | } |
| | | |
| | | @Override |
| | | public List<Device> getAll() { |
| | | return deviceMapper.getAll(); |
| | | } |
| | | } |
| | |
| | | SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null); |
| | | if (sendRtpItem != null && sendRtpItem.isOnlyAudio()) { |
| | | // 查询流是否存在,不存在则认为是异常状态 |
| | | MediaServerItem mediaServerItemInUse = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItemInUse, sendRtpItem.getApp(), sendRtpItem.getStreamId()); |
| | | MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, sendRtpItem.getApp(), sendRtpItem.getStreamId()); |
| | | if (streamReady) { |
| | | logger.warn("语音广播已经开启: {}", channelId); |
| | | event.call("语音广播已经开启"); |
| | |
| | | // 存储数据到stream_push表 |
| | | streamPushMapper.addAll(streamPushItems); |
| | | List<StreamPushItem> streamPushItemForGbStream = streamPushItems.stream() |
| | | .filter(streamPushItem-> streamPushItem.getId() != null) |
| | | .filter(streamPushItem-> streamPushItem.getGbId() != null) |
| | | .collect(Collectors.toList()); |
| | | // 存储数据到gb_stream表, id会返回到streamPushItemForGbStream里 |
| | | if (streamPushItemForGbStream.size() > 0) { |
| | |
| | | |
| | | List<SendRtpItem> queryAllSendRTPServer(); |
| | | |
| | | List<Device> getAllDevices(); |
| | | |
| | | void removeAllDevice(); |
| | | } |
| | |
| | | * @param count 每页数量 |
| | | * @return |
| | | */ |
| | | public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, Boolean catalogUnderDevice, int page, int count); |
| | | public PageInfo<DeviceChannel> queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, Boolean catalogUnderDevice, int page, int count); |
| | | |
| | | public List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String query, Boolean hasSubChannel, Boolean online, int start, int limit,List<String> channelIds); |
| | | |
| | |
| | | package com.genersoft.iot.vmp.storager.dao; |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannelInPlatform; |
| | | import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; |
| | |
| | | |
| | | @Select("select count(1) as total, sum(status) as online from device_channel") |
| | | ResourceBaceInfo getOverview(); |
| | | |
| | | @Select("select channelId" + |
| | | ", deviceId" + |
| | | ", latitude" + |
| | | ", longitude" + |
| | | ", latitudeWgs84" + |
| | | ", longitudeWgs84" + |
| | | ", latitudeGcj02" + |
| | | ", longitudeGcj02 " + |
| | | "from device_channel where deviceId = #{deviceId} " + |
| | | "and latitude != 0 " + |
| | | "and longitude != 0 " + |
| | | "and (latitudeGcj02 = 0 or latitudeWgs84 = 0 or longitudeWgs84 = 0 or longitudeGcj02 = 0)") |
| | | List<DeviceChannel> getChannelsWithoutTransform(String deviceId); |
| | | |
| | | @Select("select de.* from device de left join device_channel dc on de.deviceId = dc.deviceId where dc.channelId=#{channelId}") |
| | | List<Device> getDeviceByChannelId(String channelId); |
| | | } |
| | |
| | | @Select("select count(1) as total, sum(online) as online from device") |
| | | ResourceBaceInfo getOverview(); |
| | | |
| | | @Select("select * from device") |
| | | List<Device> getAll(); |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void removeAllDevice() { |
| | | String scanKey = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId() + "_*"; |
| | | List<Object> keys = RedisUtil.scan(scanKey); |
| | | for (Object key : keys) { |
| | | RedisUtil.del((String) key); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public List<Device> getAllDevices() { |
| | | String scanKey = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId() + "_*"; |
| | | List<Device> result = new ArrayList<>(); |
| | | List<Object> keys = RedisUtil.scan(scanKey); |
| | | for (Object o : keys) { |
| | | String key = (String) o; |
| | | Device device = JsonUtil.redisJsonToObject(key, Device.class); |
| | | if (Objects.nonNull(device)) { // 只取没有存过得 |
| | | result.add(JsonUtil.redisJsonToObject(key, Device.class)); |
| | | } |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public Device getDevice(String deviceId) { |
| | | String key = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId() + "_" + deviceId; |
| | | return JsonUtil.redisJsonToObject(key, Device.class); |
| | |
| | | if (allChannelMap.containsKey(deviceChannel.getChannelId())) { |
| | | deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId()); |
| | | deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio()); |
| | | deviceChannel.setUpdateTime(DateUtil.getNow()); |
| | | updateChannels.add(deviceChannel); |
| | | }else { |
| | | deviceChannel.setCreateTime(DateUtil.getNow()); |
| | | addChannels.add(deviceChannel); |
| | | } |
| | | if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) { |
New file |
| | |
| | | package com.genersoft.iot.vmp.utils; |
| | | |
| | | import com.fasterxml.jackson.databind.DeserializationFeature; |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.fasterxml.jackson.databind.node.ObjectNode; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.util.Iterator; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * @author gaofuwang |
| | | * @version 1.0 |
| | | * @date 2022/3/11 10:17 |
| | | */ |
| | | public class UJson { |
| | | |
| | | private static Logger logger = LoggerFactory.getLogger(UJson.class); |
| | | public static final ObjectMapper JSON_MAPPER = new ObjectMapper(); |
| | | |
| | | static { |
| | | JSON_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false); |
| | | } |
| | | |
| | | private ObjectNode node; |
| | | |
| | | public UJson(){ |
| | | this.node = JSON_MAPPER.createObjectNode(); |
| | | } |
| | | |
| | | public UJson(String json){ |
| | | if(StringUtils.isBlank(json)){ |
| | | this.node = JSON_MAPPER.createObjectNode(); |
| | | }else{ |
| | | try { |
| | | this.node = JSON_MAPPER.readValue(json, ObjectNode.class); |
| | | }catch (Exception e){ |
| | | logger.error(e.getMessage(), e); |
| | | this.node = JSON_MAPPER.createObjectNode(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public UJson(ObjectNode node){ |
| | | this.node = node; |
| | | } |
| | | |
| | | public String asText(String key){ |
| | | JsonNode jsonNode = node.get(key); |
| | | if(Objects.isNull(jsonNode)){ |
| | | return ""; |
| | | } |
| | | return jsonNode.asText(); |
| | | } |
| | | |
| | | public String asText(String key, String defaultVal){ |
| | | JsonNode jsonNode = node.get(key); |
| | | if(Objects.isNull(jsonNode)){ |
| | | return ""; |
| | | } |
| | | return jsonNode.asText(defaultVal); |
| | | } |
| | | |
| | | public UJson put(String key, String value){ |
| | | this.node.put(key, value); |
| | | return this; |
| | | } |
| | | |
| | | public UJson put(String key, Integer value){ |
| | | this.node.put(key, value); |
| | | return this; |
| | | } |
| | | |
| | | public static UJson json(){ |
| | | return new UJson(); |
| | | } |
| | | |
| | | public static UJson json(String json){ |
| | | return new UJson(json); |
| | | } |
| | | |
| | | public static <T> T readJson(String json, Class<T> clazz){ |
| | | if(StringUtils.isBlank(json)){ |
| | | return null; |
| | | } |
| | | try { |
| | | return JSON_MAPPER.readValue(json, clazz); |
| | | }catch (Exception e){ |
| | | logger.error(e.getMessage(), e); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | public static String writeJson(Object object) { |
| | | try{ |
| | | return JSON_MAPPER.writeValueAsString(object); |
| | | }catch (Exception e){ |
| | | logger.error(e.getMessage(), e); |
| | | return ""; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return node.toString(); |
| | | } |
| | | |
| | | public int asInt(String key, int defValue) { |
| | | JsonNode jsonNode = this.node.get(key); |
| | | if(Objects.isNull(jsonNode)){ |
| | | return defValue; |
| | | } |
| | | return jsonNode.asInt(defValue); |
| | | } |
| | | |
| | | public UJson getSon(String key) { |
| | | JsonNode sonNode = this.node.get(key); |
| | | if(Objects.isNull(sonNode)){ |
| | | return new UJson(); |
| | | } |
| | | return new UJson((ObjectNode) sonNode); |
| | | } |
| | | |
| | | public UJson set(String key, ObjectNode sonNode) { |
| | | this.node.set(key, sonNode); |
| | | return this; |
| | | } |
| | | |
| | | public UJson set(String key, UJson sonNode) { |
| | | this.node.set(key, sonNode.node); |
| | | return this; |
| | | } |
| | | |
| | | public Iterator<Map.Entry<String, JsonNode>> fields() { |
| | | return this.node.fields(); |
| | | } |
| | | |
| | | public ObjectNode getNode() { |
| | | return this.node; |
| | | } |
| | | |
| | | public UJson setAll(UJson json) { |
| | | this.node.setAll(json.node); |
| | | return this; |
| | | } |
| | | } |
| | |
| | | * @param time 时间
|
| | | * @return true / false
|
| | | */
|
| | | public static boolean hmset(String key, Map<Object, Object> map, long time) {
|
| | | public static boolean hmset(String key, Map<?, ?> map, long time) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | |
| | | package com.genersoft.iot.vmp.vmanager.bean; |
| | | |
| | | import com.genersoft.iot.vmp.common.StreamInfo; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | |
| | | @Schema(description = "流信息") |
| | | public class StreamContent { |
| | | |
| | | @Schema(description = "应用名") |
| | | private String app; |
| | | |
| | | @Schema(description = "流ID") |
| | | private String stream; |
| | | |
| | | @Schema(description = "IP") |
| | | private String ip; |
| | | |
| | | @Schema(description = "HTTP-FLV流地址") |
| | | private String flv; |
| | | |
| | | @Schema(description = "HTTPS-FLV流地址") |
| | | private String https_flv; |
| | | |
| | | @Schema(description = "Websocket-FLV流地址") |
| | | private String ws_flv; |
| | | |
| | | @Schema(description = "Websockets-FLV流地址") |
| | | private String wss_flv; |
| | | |
| | | @Schema(description = "HTTP-FMP4流地址") |
| | | private String fmp4; |
| | | |
| | | @Schema(description = "HTTPS-FMP4流地址") |
| | | private String https_fmp4; |
| | | |
| | | @Schema(description = "Websocket-FMP4流地址") |
| | | private String ws_fmp4; |
| | | |
| | | @Schema(description = "Websockets-FMP4流地址") |
| | | private String wss_fmp4; |
| | | |
| | | @Schema(description = "HLS流地址") |
| | | private String hls; |
| | | |
| | | @Schema(description = "HTTPS-HLS流地址") |
| | | private String https_hls; |
| | | |
| | | @Schema(description = "Websocket-HLS流地址") |
| | | private String ws_hls; |
| | | |
| | | @Schema(description = "Websockets-HLS流地址") |
| | | private String wss_hls; |
| | | |
| | | @Schema(description = "HTTP-TS流地址") |
| | | private String ts; |
| | | |
| | | @Schema(description = "HTTPS-TS流地址") |
| | | private String https_ts; |
| | | |
| | | @Schema(description = "Websocket-TS流地址") |
| | | private String ws_ts; |
| | | |
| | | @Schema(description = "Websockets-TS流地址") |
| | | private String wss_ts; |
| | | |
| | | @Schema(description = "RTMP流地址") |
| | | private String rtmp; |
| | | |
| | | @Schema(description = "RTMPS流地址") |
| | | private String rtmps; |
| | | |
| | | @Schema(description = "RTSP流地址") |
| | | private String rtsp; |
| | | |
| | | @Schema(description = "RTSPS流地址") |
| | | private String rtsps; |
| | | |
| | | @Schema(description = "RTC流地址") |
| | | private String rtc; |
| | | |
| | | @Schema(description = "RTCS流地址") |
| | | private String rtcs; |
| | | |
| | | @Schema(description = "流媒体ID") |
| | | private String mediaServerId; |
| | | |
| | | @Schema(description = "流编码信息") |
| | | private Object tracks; |
| | | |
| | | @Schema(description = "开始时间") |
| | | private String startTime; |
| | | |
| | | @Schema(description = "结束时间") |
| | | private String endTime; |
| | | |
| | | private double progress; |
| | |
| | | package com.genersoft.iot.vmp.vmanager.gb28181.MobilePosition; |
| | | |
| | | import java.text.ParseException; |
| | | import java.util.List; |
| | | import java.util.UUID; |
| | | |
| | | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| | | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| | | import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
| | | 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.service.IDeviceChannelService; |
| | | import com.genersoft.iot.vmp.service.IDeviceService; |
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| | | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| | | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| | | import com.github.pagehelper.util.StringUtil; |
| | | |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.web.bind.annotation.CrossOrigin; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.context.request.async.DeferredResult; |
| | | |
| | | import javax.sip.InvalidArgumentException; |
| | | import javax.sip.SipException; |
| | | import java.text.ParseException; |
| | | import java.util.List; |
| | | import java.util.UUID; |
| | | |
| | | /** |
| | | * 位置信息管理 |
| | |
| | | |
| | | @Autowired |
| | | private IDeviceService deviceService; |
| | | |
| | | @Autowired |
| | | private IDeviceChannelService deviceChannelService; |
| | | |
| | | /** |
| | | * 查询历史轨迹 |
| | |
| | | throw new ControllerException(ErrorCode.ERROR100); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 数据位置信息格式处理 |
| | | * @param deviceId 设备ID |
| | | * @return true = 命令发送成功 |
| | | */ |
| | | @Operation(summary = "数据位置信息格式处理") |
| | | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| | | @GetMapping("/transform/{deviceId}") |
| | | public void positionTransform(@PathVariable String deviceId) { |
| | | |
| | | Device device = deviceService.getDevice(deviceId); |
| | | if (device == null) { |
| | | throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到设备: " + deviceId); |
| | | } |
| | | boolean result = deviceChannelService.updateAllGps(device); |
| | | if (!result) { |
| | | throw new ControllerException(ErrorCode.ERROR100); |
| | | } |
| | | } |
| | | } |
| | |
| | | @Parameter(name = "online", description = "是否在线") |
| | | @Parameter(name = "channelType", description = "设备/子目录-> false/true") |
| | | @Parameter(name = "catalogUnderDevice", description = "是否直属与设备的目录") |
| | | public PageInfo channels(@PathVariable String deviceId, |
| | | public PageInfo<DeviceChannel> channels(@PathVariable String deviceId, |
| | | int page, int count, |
| | | @RequestParam(required = false) String query, |
| | | @RequestParam(required = false) Boolean online, |
| | |
| | | @Parameter(name = "online", description = "是否在线") |
| | | @Parameter(name = "channelType", description = "设备/子目录-> false/true") |
| | | @GetMapping("/sub_channels/{deviceId}/{channelId}/channels") |
| | | public PageInfo subChannels(@PathVariable String deviceId, |
| | | public PageInfo<DeviceChannel> subChannels(@PathVariable String deviceId, |
| | | @PathVariable String channelId, |
| | | int page, |
| | | int count, |
| | |
| | | return deviceChannelPageResult; |
| | | } |
| | | |
| | | PageInfo pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count); |
| | | return pageResult; |
| | | return storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count); |
| | | } |
| | | |
| | | /** |
| | |
| | | props: ['recordFile', 'mediaServerId', 'dateFiles', 'mediaServerPath'], |
| | | data() { |
| | | return { |
| | | basePath: `${this.mediaServerPath}/record`, |
| | | basePath: `${this.mediaServerPath}`, |
| | | dateFilesObj: [], |
| | | detailFiles: [], |
| | | chooseDate: null, |