diff --git a/src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java b/src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java index 886d6fa1..be573166 100644 --- a/src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java +++ b/src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java @@ -1,63 +1,63 @@ -package com.genersoft.iot.vmp; - -import com.genersoft.iot.vmp.utils.GitUtil; -import com.genersoft.iot.vmp.utils.SpringBeanFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.web.servlet.ServletComponentScan; -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.scheduling.annotation.EnableScheduling; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.SessionCookieConfig; -import javax.servlet.SessionTrackingMode; -import java.util.Collections; - -/** - * 启动类 - */ -@ServletComponentScan("com.genersoft.iot.vmp.conf") -@SpringBootApplication -@EnableScheduling -public class VManageBootstrap extends SpringBootServletInitializer { - - private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class); - - private static String[] args; - private static ConfigurableApplicationContext context; - public static void main(String[] args) { - VManageBootstrap.args = args; - VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); - GitUtil gitUtil1 = SpringBeanFactory.getBean("gitUtil"); - logger.info("构建版本: {}", gitUtil1.getBuildVersion()); - logger.info("构建时间: {}", gitUtil1.getBuildDate()); - logger.info("GIT最后提交时间: {}", gitUtil1.getCommitTime()); - } - // 项目重启 - public static void restart() { - context.close(); - VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); - } - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { - return application.sources(VManageBootstrap.class); - } - - @Override - public void onStartup(ServletContext servletContext) throws ServletException { - super.onStartup(servletContext); - - servletContext.setSessionTrackingModes( - Collections.singleton(SessionTrackingMode.COOKIE) - ); - SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig(); - sessionCookieConfig.setHttpOnly(true); - - } -} +package com.genersoft.iot.vmp; + +import com.genersoft.iot.vmp.utils.GitUtil; +import com.genersoft.iot.vmp.utils.SpringBeanFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.ServletComponentScan; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.scheduling.annotation.EnableScheduling; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import java.util.Collections; + +/** + * 启动类 + */ +@ServletComponentScan("com.genersoft.iot.vmp.conf") +@SpringBootApplication +@EnableScheduling +public class VManageBootstrap extends SpringBootServletInitializer { + + private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class); + + private static String[] args; + private static ConfigurableApplicationContext context; + public static void main(String[] args) { + VManageBootstrap.args = args; + VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); + GitUtil gitUtil1 = SpringBeanFactory.getBean("gitUtil"); + logger.info("构建版本: {}", gitUtil1.getBuildVersion()); + logger.info("构建时间: {}", gitUtil1.getBuildDate()); + logger.info("GIT最后提交时间: {}", gitUtil1.getCommitTime()); + } + // 项目重启 + public static void restart() { + context.close(); + VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(VManageBootstrap.class); + } + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + super.onStartup(servletContext); + + servletContext.setSessionTrackingModes( + Collections.singleton(SessionTrackingMode.COOKIE) + ); + SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig(); + sessionCookieConfig.setHttpOnly(true); + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java index 130f49de..5a11d4db 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java +++ b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java @@ -1,176 +1,176 @@ -package com.genersoft.iot.vmp.common; - -/** - * @description: 定义常量 - * @author: swwheihei - * @date: 2019年5月30日 下午3:04:04 - * - */ -public class VideoManagerConstants { - - public static final String WVP_SERVER_PREFIX = "VMP_SIGNALLING_SERVER_INFO_"; - - public static final String WVP_SERVER_STREAM_PREFIX = "VMP_SIGNALLING_STREAM_"; - - public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_"; - - public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_"; - - public static final String DEVICE_PREFIX = "VMP_DEVICE_"; - - // 设备同步完成 - public static final String DEVICE_SYNC_PREFIX = "VMP_DEVICE_SYNC_"; - - public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_"; - - public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_"; - - // TODO 此处多了一个_,暂不修改 - public static final String INVITE_PREFIX = "VMP_INVITE"; - public static final String PLAYER_PREFIX = "VMP_INVITE_PLAY_"; - public static final String PLAY_BLACK_PREFIX = "VMP_INVITE_PLAYBACK_"; - public static final String DOWNLOAD_PREFIX = "VMP_INVITE_DOWNLOAD_"; - - public static final String PLATFORM_KEEPALIVE_PREFIX = "VMP_PLATFORM_KEEPALIVE_"; - - public static final String PLATFORM_CATCH_PREFIX = "VMP_PLATFORM_CATCH_"; - - public static final String PLATFORM_REGISTER_PREFIX = "VMP_PLATFORM_REGISTER_"; - - public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_"; - - public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_PLATFORM_SEND_RTP_INFO_"; - - public static final String EVENT_ONLINE_REGISTER = "1"; - - public static final String EVENT_ONLINE_MESSAGE = "3"; - - public static final String EVENT_OUTLINE_UNREGISTER = "1"; - - public static final String EVENT_OUTLINE_TIMEOUT = "2"; - - public static final String MEDIA_SSRC_USED_PREFIX = "VMP_MEDIA_USED_SSRC_"; - - public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_"; - - public static final String MEDIA_STREAM_AUTHORITY = "MEDIA_STREAM_AUTHORITY_"; - - public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_"; - - public static final String SIP_SN_PREFIX = "VMP_SIP_SN_"; - - public static final String SIP_SUBSCRIBE_PREFIX = "VMP_SIP_SUBSCRIBE_"; - - public static final String SYSTEM_INFO_CPU_PREFIX = "VMP_SYSTEM_INFO_CPU_"; - - public static final String SYSTEM_INFO_MEM_PREFIX = "VMP_SYSTEM_INFO_MEM_"; - - public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_"; - - public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_"; - - public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_"; - - - - - //************************** redis 消息********************************* - - /** - * 流变化的通知 - */ - public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_"; - - /** - * 接收推流设备的GPS变化通知 - */ - public static final String VM_MSG_GPS = "VM_MSG_GPS"; - - /** - * 接收推流设备的GPS变化通知 - */ - public static final String VM_MSG_PUSH_STREAM_STATUS_CHANGE = "VM_MSG_PUSH_STREAM_STATUS_CHANGE"; - /** - * 接收推流设备列表更新变化通知 - */ - public static final String VM_MSG_PUSH_STREAM_LIST_CHANGE = "VM_MSG_PUSH_STREAM_LIST_CHANGE"; - - /** - * redis 消息通知设备推流到平台 - */ - public static final String VM_MSG_STREAM_PUSH_REQUESTED = "VM_MSG_STREAM_PUSH_REQUESTED"; - - /** - * redis 消息通知上级平台开始观看流 - */ - public static final String VM_MSG_STREAM_START_PLAY_NOTIFY = "VM_MSG_STREAM_START_PLAY_NOTIFY"; - - /** - * redis 消息通知上级平台停止观看流 - */ - public static final String VM_MSG_STREAM_STOP_PLAY_NOTIFY = "VM_MSG_STREAM_STOP_PLAY_NOTIFY"; - - /** - * redis 消息接收关闭一个推流 - */ - public static final String VM_MSG_STREAM_PUSH_CLOSE_REQUESTED = "VM_MSG_STREAM_PUSH_CLOSE_REQUESTED"; - - - /** - * redis 消息通知平台通知设备推流结果 - */ - public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE"; - - /** - * redis 通知平台关闭推流 - */ - public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE"; - - /** - * redis 消息请求所有的在线通道 - */ - public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED"; - - /** - * 移动位置订阅通知 - */ - public static final String VM_MSG_SUBSCRIBE_MOBILE_POSITION = "mobileposition"; - - /** - * 报警订阅的通知(收到报警向redis发出通知) - */ - public static final String VM_MSG_SUBSCRIBE_ALARM = "alarm"; - - - /** - * 报警通知的发送 (收到redis发出的通知,转发给其他平台) - */ - public static final String VM_MSG_SUBSCRIBE_ALARM_RECEIVE= "alarm_receive"; - - /** - * 设备状态订阅的通知 - */ - public static final String VM_MSG_SUBSCRIBE_DEVICE_STATUS = "device"; - - - //************************** 第三方 **************************************** - - public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; - public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; - public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_"; - public static final String WVP_OTHER_SEND_PS_INFO = "VMP_OTHER_SEND_PS_INFO_"; - public static final String WVP_OTHER_RECEIVE_RTP_INFO = "VMP_OTHER_RECEIVE_RTP_INFO_"; - public static final String WVP_OTHER_RECEIVE_PS_INFO = "VMP_OTHER_RECEIVE_PS_INFO_"; - - /** - * 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:"; - -} +package com.genersoft.iot.vmp.common; + +/** + * @description: 定义常量 + * @author: swwheihei + * @date: 2019年5月30日 下午3:04:04 + * + */ +public class VideoManagerConstants { + + public static final String WVP_SERVER_PREFIX = "VMP_SIGNALLING_SERVER_INFO_"; + + public static final String WVP_SERVER_STREAM_PREFIX = "VMP_SIGNALLING_STREAM_"; + + public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_"; + + public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_"; + + public static final String DEVICE_PREFIX = "VMP_DEVICE_"; + + // 设备同步完成 + public static final String DEVICE_SYNC_PREFIX = "VMP_DEVICE_SYNC_"; + + public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_"; + + public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_"; + + // TODO 此处多了一个_,暂不修改 + public static final String INVITE_PREFIX = "VMP_INVITE"; + public static final String PLAYER_PREFIX = "VMP_INVITE_PLAY_"; + public static final String PLAY_BLACK_PREFIX = "VMP_INVITE_PLAYBACK_"; + public static final String DOWNLOAD_PREFIX = "VMP_INVITE_DOWNLOAD_"; + + public static final String PLATFORM_KEEPALIVE_PREFIX = "VMP_PLATFORM_KEEPALIVE_"; + + public static final String PLATFORM_CATCH_PREFIX = "VMP_PLATFORM_CATCH_"; + + public static final String PLATFORM_REGISTER_PREFIX = "VMP_PLATFORM_REGISTER_"; + + public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_"; + + public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_PLATFORM_SEND_RTP_INFO_"; + + public static final String EVENT_ONLINE_REGISTER = "1"; + + public static final String EVENT_ONLINE_MESSAGE = "3"; + + public static final String EVENT_OUTLINE_UNREGISTER = "1"; + + public static final String EVENT_OUTLINE_TIMEOUT = "2"; + + public static final String MEDIA_SSRC_USED_PREFIX = "VMP_MEDIA_USED_SSRC_"; + + public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_"; + + public static final String MEDIA_STREAM_AUTHORITY = "MEDIA_STREAM_AUTHORITY_"; + + public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_"; + + public static final String SIP_SN_PREFIX = "VMP_SIP_SN_"; + + public static final String SIP_SUBSCRIBE_PREFIX = "VMP_SIP_SUBSCRIBE_"; + + public static final String SYSTEM_INFO_CPU_PREFIX = "VMP_SYSTEM_INFO_CPU_"; + + public static final String SYSTEM_INFO_MEM_PREFIX = "VMP_SYSTEM_INFO_MEM_"; + + public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_"; + + public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_"; + + public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_"; + + + + + //************************** redis 消息********************************* + + /** + * 流变化的通知 + */ + public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_"; + + /** + * 接收推流设备的GPS变化通知 + */ + public static final String VM_MSG_GPS = "VM_MSG_GPS"; + + /** + * 接收推流设备的GPS变化通知 + */ + public static final String VM_MSG_PUSH_STREAM_STATUS_CHANGE = "VM_MSG_PUSH_STREAM_STATUS_CHANGE"; + /** + * 接收推流设备列表更新变化通知 + */ + public static final String VM_MSG_PUSH_STREAM_LIST_CHANGE = "VM_MSG_PUSH_STREAM_LIST_CHANGE"; + + /** + * redis 消息通知设备推流到平台 + */ + public static final String VM_MSG_STREAM_PUSH_REQUESTED = "VM_MSG_STREAM_PUSH_REQUESTED"; + + /** + * redis 消息通知上级平台开始观看流 + */ + public static final String VM_MSG_STREAM_START_PLAY_NOTIFY = "VM_MSG_STREAM_START_PLAY_NOTIFY"; + + /** + * redis 消息通知上级平台停止观看流 + */ + public static final String VM_MSG_STREAM_STOP_PLAY_NOTIFY = "VM_MSG_STREAM_STOP_PLAY_NOTIFY"; + + /** + * redis 消息接收关闭一个推流 + */ + public static final String VM_MSG_STREAM_PUSH_CLOSE_REQUESTED = "VM_MSG_STREAM_PUSH_CLOSE_REQUESTED"; + + + /** + * redis 消息通知平台通知设备推流结果 + */ + public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE"; + + /** + * redis 通知平台关闭推流 + */ + public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE"; + + /** + * redis 消息请求所有的在线通道 + */ + public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED"; + + /** + * 移动位置订阅通知 + */ + public static final String VM_MSG_SUBSCRIBE_MOBILE_POSITION = "mobileposition"; + + /** + * 报警订阅的通知(收到报警向redis发出通知) + */ + public static final String VM_MSG_SUBSCRIBE_ALARM = "alarm"; + + + /** + * 报警通知的发送 (收到redis发出的通知,转发给其他平台) + */ + public static final String VM_MSG_SUBSCRIBE_ALARM_RECEIVE= "alarm_receive"; + + /** + * 设备状态订阅的通知 + */ + public static final String VM_MSG_SUBSCRIBE_DEVICE_STATUS = "device"; + + + //************************** 第三方 **************************************** + + public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; + public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; + public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_"; + public static final String WVP_OTHER_SEND_PS_INFO = "VMP_OTHER_SEND_PS_INFO_"; + public static final String WVP_OTHER_RECEIVE_RTP_INFO = "VMP_OTHER_RECEIVE_RTP_INFO_"; + public static final String WVP_OTHER_RECEIVE_PS_INFO = "VMP_OTHER_RECEIVE_PS_INFO_"; + + /** + * 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:"; + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java index 0c77fc18..56663f18 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java @@ -1,141 +1,141 @@ -package com.genersoft.iot.vmp.gb28181; - -import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.gb28181.bean.GbStringMsgParserFactory; -import com.genersoft.iot.vmp.gb28181.conf.DefaultProperties; -import com.genersoft.iot.vmp.gb28181.transmit.ISIPProcessorObserver; -import gov.nist.javax.sip.SipProviderImpl; -import gov.nist.javax.sip.SipStackImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.CommandLineRunner; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; -import org.springframework.util.ObjectUtils; - -import javax.sip.*; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -@Component -@Order(value=10) -public class SipLayer implements CommandLineRunner { - - private final static Logger logger = LoggerFactory.getLogger(SipLayer.class); - - @Autowired - private SipConfig sipConfig; - - @Autowired - private ISIPProcessorObserver sipProcessorObserver; - - @Autowired - private UserSetting userSetting; - - private final Map tcpSipProviderMap = new ConcurrentHashMap<>(); - private final Map udpSipProviderMap = new ConcurrentHashMap<>(); - - @Override - public void run(String... args) { - List monitorIps = new ArrayList<>(); - // 使用逗号分割多个ip - String separator = ","; - if (sipConfig.getIp().indexOf(separator) > 0) { - String[] split = sipConfig.getIp().split(separator); - monitorIps.addAll(Arrays.asList(split)); - }else { - monitorIps.add(sipConfig.getIp()); - } - - SipFactory.getInstance().setPathName("gov.nist"); - if (monitorIps.size() > 0) { - for (String monitorIp : monitorIps) { - addListeningPoint(monitorIp, sipConfig.getPort()); - } - if (udpSipProviderMap.size() + tcpSipProviderMap.size() == 0) { - System.exit(1); - } - } - } - - private void addListeningPoint(String monitorIp, int port){ - SipStackImpl sipStack; - try { - sipStack = (SipStackImpl)SipFactory.getInstance().createSipStack(DefaultProperties.getProperties("GB28181_SIP", userSetting.getSipLog())); - sipStack.setMessageParserFactory(new GbStringMsgParserFactory()); - } catch (PeerUnavailableException e) { - logger.error("[SIP SERVER] SIP服务启动失败, 监听地址{}失败,请检查ip是否正确", monitorIp); - return; - } - - try { - ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "TCP"); - SipProviderImpl tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint); - - tcpSipProvider.setDialogErrorsAutomaticallyHandled(); - tcpSipProvider.addSipListener(sipProcessorObserver); - tcpSipProviderMap.put(monitorIp, tcpSipProvider); - logger.info("[SIP SERVER] tcp://{}:{} 启动成功", monitorIp, port); - } catch (TransportNotSupportedException - | TooManyListenersException - | ObjectInUseException - | InvalidArgumentException e) { - logger.error("[SIP SERVER] tcp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确" - , monitorIp, port); - } - - try { - ListeningPoint udpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "UDP"); - - SipProviderImpl udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint); - udpSipProvider.addSipListener(sipProcessorObserver); - - udpSipProviderMap.put(monitorIp, udpSipProvider); - - logger.info("[SIP SERVER] udp://{}:{} 启动成功", monitorIp, port); - } catch (TransportNotSupportedException - | TooManyListenersException - | ObjectInUseException - | InvalidArgumentException e) { - logger.error("[SIP SERVER] udp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确" - , monitorIp, port); - } - } - - public SipProviderImpl getUdpSipProvider(String ip) { - if (ObjectUtils.isEmpty(ip)) { - return null; - } - return udpSipProviderMap.get(ip); - } - - public SipProviderImpl getUdpSipProvider() { - if (udpSipProviderMap.size() != 1) { - return null; - } - return udpSipProviderMap.values().stream().findFirst().get(); - } - - public SipProviderImpl getTcpSipProvider() { - if (tcpSipProviderMap.size() != 1) { - return null; - } - return tcpSipProviderMap.values().stream().findFirst().get(); - } - - public SipProviderImpl getTcpSipProvider(String ip) { - if (ObjectUtils.isEmpty(ip)) { - return null; - } - return tcpSipProviderMap.get(ip); - } - - public String getLocalIp(String deviceLocalIp) { - if (!ObjectUtils.isEmpty(deviceLocalIp)) { - return deviceLocalIp; - } - return getUdpSipProvider().getListeningPoint().getIPAddress(); - } -} +package com.genersoft.iot.vmp.gb28181; + +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.gb28181.bean.GbStringMsgParserFactory; +import com.genersoft.iot.vmp.gb28181.conf.DefaultProperties; +import com.genersoft.iot.vmp.gb28181.transmit.ISIPProcessorObserver; +import gov.nist.javax.sip.SipProviderImpl; +import gov.nist.javax.sip.SipStackImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import javax.sip.*; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +@Component +@Order(value=10) +public class SipLayer implements CommandLineRunner { + + private final static Logger logger = LoggerFactory.getLogger(SipLayer.class); + + @Autowired + private SipConfig sipConfig; + + @Autowired + private ISIPProcessorObserver sipProcessorObserver; + + @Autowired + private UserSetting userSetting; + + private final Map tcpSipProviderMap = new ConcurrentHashMap<>(); + private final Map udpSipProviderMap = new ConcurrentHashMap<>(); + + @Override + public void run(String... args) { + List monitorIps = new ArrayList<>(); + // 使用逗号分割多个ip + String separator = ","; + if (sipConfig.getIp().indexOf(separator) > 0) { + String[] split = sipConfig.getIp().split(separator); + monitorIps.addAll(Arrays.asList(split)); + }else { + monitorIps.add(sipConfig.getIp()); + } + + SipFactory.getInstance().setPathName("gov.nist"); + if (monitorIps.size() > 0) { + for (String monitorIp : monitorIps) { + addListeningPoint(monitorIp, sipConfig.getPort()); + } + if (udpSipProviderMap.size() + tcpSipProviderMap.size() == 0) { + System.exit(1); + } + } + } + + private void addListeningPoint(String monitorIp, int port){ + SipStackImpl sipStack; + try { + sipStack = (SipStackImpl)SipFactory.getInstance().createSipStack(DefaultProperties.getProperties("GB28181_SIP", userSetting.getSipLog())); + sipStack.setMessageParserFactory(new GbStringMsgParserFactory()); + } catch (PeerUnavailableException e) { + logger.error("[SIP SERVER] SIP服务启动失败, 监听地址{}失败,请检查ip是否正确", monitorIp); + return; + } + + try { + ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "TCP"); + SipProviderImpl tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint); + + tcpSipProvider.setDialogErrorsAutomaticallyHandled(); + tcpSipProvider.addSipListener(sipProcessorObserver); + tcpSipProviderMap.put(monitorIp, tcpSipProvider); + logger.info("[SIP SERVER] tcp://{}:{} 启动成功", monitorIp, port); + } catch (TransportNotSupportedException + | TooManyListenersException + | ObjectInUseException + | InvalidArgumentException e) { + logger.error("[SIP SERVER] tcp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确" + , monitorIp, port); + } + + try { + ListeningPoint udpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "UDP"); + + SipProviderImpl udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint); + udpSipProvider.addSipListener(sipProcessorObserver); + + udpSipProviderMap.put(monitorIp, udpSipProvider); + + logger.info("[SIP SERVER] udp://{}:{} 启动成功", monitorIp, port); + } catch (TransportNotSupportedException + | TooManyListenersException + | ObjectInUseException + | InvalidArgumentException e) { + logger.error("[SIP SERVER] udp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确" + , monitorIp, port); + } + } + + public SipProviderImpl getUdpSipProvider(String ip) { + if (ObjectUtils.isEmpty(ip)) { + return null; + } + return udpSipProviderMap.get(ip); + } + + public SipProviderImpl getUdpSipProvider() { + if (udpSipProviderMap.size() != 1) { + return null; + } + return udpSipProviderMap.values().stream().findFirst().get(); + } + + public SipProviderImpl getTcpSipProvider() { + if (tcpSipProviderMap.size() != 1) { + return null; + } + return tcpSipProviderMap.values().stream().findFirst().get(); + } + + public SipProviderImpl getTcpSipProvider(String ip) { + if (ObjectUtils.isEmpty(ip)) { + return null; + } + return tcpSipProviderMap.get(ip); + } + + public String getLocalIp(String deviceLocalIp) { + if (!ObjectUtils.isEmpty(deviceLocalIp)) { + return deviceLocalIp; + } + return getUdpSipProvider().getListeningPoint().getIPAddress(); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java index bfc97b55..37113416 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java @@ -1,187 +1,187 @@ -package com.genersoft.iot.vmp.gb28181.bean; - -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @author lin - */ -@Schema(description = "报警信息") -public class DeviceAlarm { - - /** - * 数据库id - */ - @Schema(description = "数据库id") - private String id; - - /** - * 设备Id - */ - @Schema(description = "设备的国标编号") - private String deviceId; - - /** - * 通道Id - */ - @Schema(description = "通道的国标编号") - private String channelId; - - /** - * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情 - */ - @Schema(description = "报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情") - private String alarmPriority; - - /** - * 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警, - * 7其他报警;可以为直接组合如12为电话报警或 设备报警- - */ - @Schema(description = "报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,\n" + - "\t * 7其他报警;可以为直接组合如12为电话报警或设备报警") - private String alarmMethod; - - /** - * 报警时间 - */ - @Schema(description = "报警时间") - private String alarmTime; - - /** - * 报警内容描述 - */ - @Schema(description = "报警内容描述") - private String alarmDescription; - - /** - * 经度 - */ - @Schema(description = "经度") - private double longitude; - - /** - * 纬度 - */ - @Schema(description = "纬度") - private double latitude; - - /** - * 报警类型, - * 报警方式为2时,不携带 AlarmType为默认的报警设备报警, - * 携带 AlarmType取值及对应报警类型如下: - * 1-视频丢失报警; - * 2-设备防拆报警; - * 3-存储设备磁盘满报警; - * 4-设备高温报警; - * 5-设备低温报警。 - * 报警方式为5时,取值如下: - * 1-人工视频报警; - * 2-运动目标检测报警; - * 3-遗留物检测报警; - * 4-物体移除检测报警; - * 5-绊线检测报警; - * 6-入侵检测报警; - * 7-逆行检测报警; - * 8-徘徊检测报警; - * 9-流量统计报警; - * 10-密度检测报警; - * 11-视频异常检测报警; - * 12-快速移动报警。 - * 报警方式为6时,取值下: - * 1-存储设备磁盘故障报警; - * 2-存储设备风扇故障报警。 - */ - @Schema(description = "报警类型") - private String alarmType; - - @Schema(description = "创建时间") - private String createTime; - - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getDeviceId() { - return deviceId; - } - - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } - - public String getAlarmPriority() { - return alarmPriority; - } - - public void setAlarmPriority(String alarmPriority) { - this.alarmPriority = alarmPriority; - } - - public String getAlarmMethod() { - return alarmMethod; - } - - public void setAlarmMethod(String alarmMethod) { - this.alarmMethod = alarmMethod; - } - - public String getAlarmTime() { - return alarmTime; - } - - public void setAlarmTime(String alarmTime) { - this.alarmTime = alarmTime; - } - - public String getAlarmDescription() { - return alarmDescription; - } - - public void setAlarmDescription(String alarmDescription) { - this.alarmDescription = alarmDescription; - } - - public double getLongitude() { - return longitude; - } - - public void setLongitude(double longitude) { - this.longitude = longitude; - } - - public double getLatitude() { - return latitude; - } - - public void setLatitude(double latitude) { - this.latitude = latitude; - } - - public String getAlarmType() { - return alarmType; - } - - public void setAlarmType(String alarmType) { - this.alarmType = alarmType; - } - - public String getChannelId() { - return channelId; - } - - public void setChannelId(String channelId) { - this.channelId = channelId; - } - - public String getCreateTime() { - return createTime; - } - - public void setCreateTime(String createTime) { - this.createTime = createTime; - } -} +package com.genersoft.iot.vmp.gb28181.bean; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * @author lin + */ +@Schema(description = "报警信息") +public class DeviceAlarm { + + /** + * 数据库id + */ + @Schema(description = "数据库id") + private String id; + + /** + * 设备Id + */ + @Schema(description = "设备的国标编号") + private String deviceId; + + /** + * 通道Id + */ + @Schema(description = "通道的国标编号") + private String channelId; + + /** + * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情 + */ + @Schema(description = "报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情") + private String alarmPriority; + + /** + * 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警, + * 7其他报警;可以为直接组合如12为电话报警或 设备报警- + */ + @Schema(description = "报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,\n" + + "\t * 7其他报警;可以为直接组合如12为电话报警或设备报警") + private String alarmMethod; + + /** + * 报警时间 + */ + @Schema(description = "报警时间") + private String alarmTime; + + /** + * 报警内容描述 + */ + @Schema(description = "报警内容描述") + private String alarmDescription; + + /** + * 经度 + */ + @Schema(description = "经度") + private double longitude; + + /** + * 纬度 + */ + @Schema(description = "纬度") + private double latitude; + + /** + * 报警类型, + * 报警方式为2时,不携带 AlarmType为默认的报警设备报警, + * 携带 AlarmType取值及对应报警类型如下: + * 1-视频丢失报警; + * 2-设备防拆报警; + * 3-存储设备磁盘满报警; + * 4-设备高温报警; + * 5-设备低温报警。 + * 报警方式为5时,取值如下: + * 1-人工视频报警; + * 2-运动目标检测报警; + * 3-遗留物检测报警; + * 4-物体移除检测报警; + * 5-绊线检测报警; + * 6-入侵检测报警; + * 7-逆行检测报警; + * 8-徘徊检测报警; + * 9-流量统计报警; + * 10-密度检测报警; + * 11-视频异常检测报警; + * 12-快速移动报警。 + * 报警方式为6时,取值下: + * 1-存储设备磁盘故障报警; + * 2-存储设备风扇故障报警。 + */ + @Schema(description = "报警类型") + private String alarmType; + + @Schema(description = "创建时间") + private String createTime; + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getAlarmPriority() { + return alarmPriority; + } + + public void setAlarmPriority(String alarmPriority) { + this.alarmPriority = alarmPriority; + } + + public String getAlarmMethod() { + return alarmMethod; + } + + public void setAlarmMethod(String alarmMethod) { + this.alarmMethod = alarmMethod; + } + + public String getAlarmTime() { + return alarmTime; + } + + public void setAlarmTime(String alarmTime) { + this.alarmTime = alarmTime; + } + + public String getAlarmDescription() { + return alarmDescription; + } + + public void setAlarmDescription(String alarmDescription) { + this.alarmDescription = alarmDescription; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public String getAlarmType() { + return alarmType; + } + + public void setAlarmType(String alarmType) { + this.alarmType = alarmType; + } + + public String getChannelId() { + return channelId; + } + + public void setChannelId(String channelId) { + this.channelId = channelId; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GBStringMsgParser.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GBStringMsgParser.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStringMsgParserFactory.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStringMsgParserFactory.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HandlerCatchData.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HandlerCatchData.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Host.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Host.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamCallback.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamCallback.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatformCatch.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatformCatch.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformRegister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformRegister.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PresetQuerySipReq.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PresetQuerySipReq.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java old mode 100644 new mode 100755 index 7ff52830..5b524cf6 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java @@ -1,102 +1,102 @@ -package com.genersoft.iot.vmp.gb28181.bean; - - -import io.swagger.v3.oas.annotations.media.Schema; - -import java.time.Instant; -import java.util.List; - -/** - * @description:设备录像信息bean - * @author: swwheihei - * @date: 2020年5月8日 下午2:05:56 - */ -@Schema(description = "设备录像查询结果信息") -public class RecordInfo { - - @Schema(description = "设备编号") - private String deviceId; - - @Schema(description = "通道编号") - private String channelId; - - @Schema(description = "命令序列号") - private String sn; - - @Schema(description = "设备名称") - private String name; - - @Schema(description = "列表总数") - private int sumNum; - - private int count; - - private Instant lastTime; - - @Schema(description = "") - private List recordList; - - public String getDeviceId() { - return deviceId; - } - - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getSumNum() { - return sumNum; - } - - public void setSumNum(int sumNum) { - this.sumNum = sumNum; - } - - public List getRecordList() { - return recordList; - } - - public void setRecordList(List recordList) { - this.recordList = recordList; - } - - public String getChannelId() { - return channelId; - } - - public void setChannelId(String channelId) { - this.channelId = channelId; - } - - public String getSn() { - return sn; - } - - public void setSn(String sn) { - this.sn = sn; - } - - public Instant getLastTime() { - return lastTime; - } - - public void setLastTime(Instant lastTime) { - this.lastTime = lastTime; - } - - public int getCount() { - return count; - } - - public void setCount(int count) { - this.count = count; - } -} +package com.genersoft.iot.vmp.gb28181.bean; + + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.time.Instant; +import java.util.List; + +/** + * @description:设备录像信息bean + * @author: swwheihei + * @date: 2020年5月8日 下午2:05:56 + */ +@Schema(description = "设备录像查询结果信息") +public class RecordInfo { + + @Schema(description = "设备编号") + private String deviceId; + + @Schema(description = "通道编号") + private String channelId; + + @Schema(description = "命令序列号") + private String sn; + + @Schema(description = "设备名称") + private String name; + + @Schema(description = "列表总数") + private int sumNum; + + private int count; + + private Instant lastTime; + + @Schema(description = "") + private List recordList; + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getSumNum() { + return sumNum; + } + + public void setSumNum(int sumNum) { + this.sumNum = sumNum; + } + + public List getRecordList() { + return recordList; + } + + public void setRecordList(List recordList) { + this.recordList = recordList; + } + + public String getChannelId() { + return channelId; + } + + public void setChannelId(String channelId) { + this.channelId = channelId; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public Instant getLastTime() { + return lastTime; + } + + public void setLastTime(Instant lastTime) { + this.lastTime = lastTime; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java old mode 100644 new mode 100755 index 07e559c8..452e1388 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java @@ -1,144 +1,144 @@ -package com.genersoft.iot.vmp.gb28181.bean; - - -import com.genersoft.iot.vmp.utils.DateUtil; -import io.swagger.v3.oas.annotations.media.Schema; -import org.jetbrains.annotations.NotNull; - -import java.time.Instant; -import java.time.temporal.TemporalAccessor; - -/** - * @description:设备录像bean - * @author: swwheihei - * @date: 2020年5月8日 下午2:06:54 - */ -@Schema(description = "设备录像详情") -public class RecordItem implements Comparable{ - - @Schema(description = "设备编号") - private String deviceId; - - @Schema(description = "名称") - private String name; - - @Schema(description = "文件路径名 (可选)") - private String filePath; - - @Schema(description = "录像文件大小,单位:Byte(可选)") - private String fileSize; - - @Schema(description = "录像地址(可选)") - private String address; - - @Schema(description = "录像开始时间(可选)") - private String startTime; - - @Schema(description = "录像结束时间(可选)") - private String endTime; - - @Schema(description = "保密属性(必选)缺省为0;0:不涉密,1:涉密") - private int secrecy; - - @Schema(description = "录像产生类型(可选)time或alarm 或 manua") - private String type; - - @Schema(description = "录像触发者ID(可选)") - private String recorderId; - - public String getDeviceId() { - return deviceId; - } - - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getFilePath() { - return filePath; - } - - public void setFilePath(String filePath) { - this.filePath = filePath; - } - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - public String getStartTime() { - return startTime; - } - - public void setStartTime(String startTime) { - this.startTime = startTime; - } - - public String getEndTime() { - return endTime; - } - - public void setEndTime(String endTime) { - this.endTime = endTime; - } - - public int getSecrecy() { - return secrecy; - } - - public void setSecrecy(int secrecy) { - this.secrecy = secrecy; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getRecorderId() { - return recorderId; - } - - public void setRecorderId(String recorderId) { - this.recorderId = recorderId; - } - - public String getFileSize() { - return fileSize; - } - - public void setFileSize(String fileSize) { - this.fileSize = fileSize; - } - - @Override - public int compareTo(@NotNull RecordItem recordItem) { - TemporalAccessor startTimeNow = DateUtil.formatter.parse(startTime); - TemporalAccessor startTimeParam = DateUtil.formatter.parse(recordItem.getStartTime()); - Instant startTimeParamInstant = Instant.from(startTimeParam); - Instant startTimeNowInstant = Instant.from(startTimeNow); - if (startTimeNowInstant.equals(startTimeParamInstant)) { - return 0; - }else if (Instant.from(startTimeParam).isAfter(Instant.from(startTimeNow)) ) { - return -1; - }else { - return 1; - } - - } -} +package com.genersoft.iot.vmp.gb28181.bean; + + +import com.genersoft.iot.vmp.utils.DateUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import org.jetbrains.annotations.NotNull; + +import java.time.Instant; +import java.time.temporal.TemporalAccessor; + +/** + * @description:设备录像bean + * @author: swwheihei + * @date: 2020年5月8日 下午2:06:54 + */ +@Schema(description = "设备录像详情") +public class RecordItem implements Comparable{ + + @Schema(description = "设备编号") + private String deviceId; + + @Schema(description = "名称") + private String name; + + @Schema(description = "文件路径名 (可选)") + private String filePath; + + @Schema(description = "录像文件大小,单位:Byte(可选)") + private String fileSize; + + @Schema(description = "录像地址(可选)") + private String address; + + @Schema(description = "录像开始时间(可选)") + private String startTime; + + @Schema(description = "录像结束时间(可选)") + private String endTime; + + @Schema(description = "保密属性(必选)缺省为0;0:不涉密,1:涉密") + private int secrecy; + + @Schema(description = "录像产生类型(可选)time或alarm 或 manua") + private String type; + + @Schema(description = "录像触发者ID(可选)") + private String recorderId; + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public int getSecrecy() { + return secrecy; + } + + public void setSecrecy(int secrecy) { + this.secrecy = secrecy; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getRecorderId() { + return recorderId; + } + + public void setRecorderId(String recorderId) { + this.recorderId = recorderId; + } + + public String getFileSize() { + return fileSize; + } + + public void setFileSize(String fileSize) { + this.fileSize = fileSize; + } + + @Override + public int compareTo(@NotNull RecordItem recordItem) { + TemporalAccessor startTimeNow = DateUtil.formatter.parse(startTime); + TemporalAccessor startTimeParam = DateUtil.formatter.parse(recordItem.getStartTime()); + Instant startTimeParamInstant = Instant.from(startTimeParam); + Instant startTimeNowInstant = Instant.from(startTimeNow); + if (startTimeNowInstant.equals(startTimeParamInstant)) { + return 0; + }else if (Instant.from(startTimeParam).isAfter(Instant.from(startTimeNow)) ) { + return -1; + }else { + return 1; + } + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SDPInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SDPInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipMsgInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipMsgInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SyncStatus.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SyncStatus.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/conf/DefaultProperties.java b/src/main/java/com/genersoft/iot/vmp/gb28181/conf/DefaultProperties.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/conf/ServerLoggerImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/conf/ServerLoggerImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/conf/StackLoggerImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/conf/StackLoggerImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java old mode 100644 new mode 100755 index 26ababd4..d56e744d --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java @@ -1,118 +1,118 @@ -package com.genersoft.iot.vmp.gb28181.event; - -import com.genersoft.iot.vmp.gb28181.bean.*; -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.media.zlm.event.ZLMOfflineEvent; -import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.stereotype.Component; - -import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent; - -import javax.sip.TimeoutEvent; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * @description:Event事件通知推送器,支持推送在线事件、离线事件 - * @author: swwheihei - * @date: 2020年5月6日 上午11:30:50 - */ -@Component -public class EventPublisher { - - @Autowired - private ApplicationEventPublisher applicationEventPublisher; - - /** - * 设备报警事件 - * @param deviceAlarm - */ - public void deviceAlarmEventPublish(DeviceAlarm deviceAlarm) { - AlarmEvent alarmEvent = new AlarmEvent(this); - alarmEvent.setAlarmInfo(deviceAlarm); - applicationEventPublisher.publishEvent(alarmEvent); - } - - public void zlmOfflineEventPublish(String mediaServerId){ - ZLMOfflineEvent outEvent = new ZLMOfflineEvent(this); - outEvent.setMediaServerId(mediaServerId); - applicationEventPublisher.publishEvent(outEvent); - } - - public void zlmOnlineEventPublish(String mediaServerId) { - ZLMOnlineEvent outEvent = new ZLMOnlineEvent(this); - outEvent.setMediaServerId(mediaServerId); - applicationEventPublisher.publishEvent(outEvent); - } - - - public void catalogEventPublish(String platformId, DeviceChannel deviceChannel, String type) { - List deviceChannelList = new ArrayList<>(); - deviceChannelList.add(deviceChannel); - catalogEventPublish(platformId, deviceChannelList, type); - } - - - public void requestTimeOut(TimeoutEvent timeoutEvent) { - RequestTimeoutEvent requestTimeoutEvent = new RequestTimeoutEvent(this); - requestTimeoutEvent.setTimeoutEvent(timeoutEvent); - applicationEventPublisher.publishEvent(requestTimeoutEvent); - } - - - /** - * - * @param platformId - * @param deviceChannels - * @param type - */ - public void catalogEventPublish(String platformId, List deviceChannels, String type) { - CatalogEvent outEvent = new CatalogEvent(this); - List channels = new ArrayList<>(); - if (deviceChannels.size() > 1) { - // 数据去重 - Set gbIdSet = new HashSet<>(); - for (DeviceChannel deviceChannel : deviceChannels) { - if (!gbIdSet.contains(deviceChannel.getChannelId())) { - gbIdSet.add(deviceChannel.getChannelId()); - channels.add(deviceChannel); - } - } - }else { - channels = deviceChannels; - } - outEvent.setDeviceChannels(channels); - outEvent.setType(type); - outEvent.setPlatformId(platformId); - applicationEventPublisher.publishEvent(outEvent); - } - - - public void catalogEventPublishForStream(String platformId, List gbStreams, String type) { - CatalogEvent outEvent = new CatalogEvent(this); - outEvent.setGbStreams(gbStreams); - outEvent.setType(type); - outEvent.setPlatformId(platformId); - applicationEventPublisher.publishEvent(outEvent); - } - - - public void catalogEventPublishForStream(String platformId, GbStream gbStream, String type) { - List gbStreamList = new ArrayList<>(); - gbStreamList.add(gbStream); - catalogEventPublishForStream(platformId, gbStreamList, type); - } - - public void recordEndEventPush(RecordInfo recordInfo) { - RecordEndEvent outEvent = new RecordEndEvent(this); - outEvent.setRecordInfo(recordInfo); - applicationEventPublisher.publishEvent(outEvent); - } - -} +package com.genersoft.iot.vmp.gb28181.event; + +import com.genersoft.iot.vmp.gb28181.bean.*; +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.media.zlm.event.ZLMOfflineEvent; +import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent; + +import javax.sip.TimeoutEvent; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @description:Event事件通知推送器,支持推送在线事件、离线事件 + * @author: swwheihei + * @date: 2020年5月6日 上午11:30:50 + */ +@Component +public class EventPublisher { + + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + + /** + * 设备报警事件 + * @param deviceAlarm + */ + public void deviceAlarmEventPublish(DeviceAlarm deviceAlarm) { + AlarmEvent alarmEvent = new AlarmEvent(this); + alarmEvent.setAlarmInfo(deviceAlarm); + applicationEventPublisher.publishEvent(alarmEvent); + } + + public void zlmOfflineEventPublish(String mediaServerId){ + ZLMOfflineEvent outEvent = new ZLMOfflineEvent(this); + outEvent.setMediaServerId(mediaServerId); + applicationEventPublisher.publishEvent(outEvent); + } + + public void zlmOnlineEventPublish(String mediaServerId) { + ZLMOnlineEvent outEvent = new ZLMOnlineEvent(this); + outEvent.setMediaServerId(mediaServerId); + applicationEventPublisher.publishEvent(outEvent); + } + + + public void catalogEventPublish(String platformId, DeviceChannel deviceChannel, String type) { + List deviceChannelList = new ArrayList<>(); + deviceChannelList.add(deviceChannel); + catalogEventPublish(platformId, deviceChannelList, type); + } + + + public void requestTimeOut(TimeoutEvent timeoutEvent) { + RequestTimeoutEvent requestTimeoutEvent = new RequestTimeoutEvent(this); + requestTimeoutEvent.setTimeoutEvent(timeoutEvent); + applicationEventPublisher.publishEvent(requestTimeoutEvent); + } + + + /** + * + * @param platformId + * @param deviceChannels + * @param type + */ + public void catalogEventPublish(String platformId, List deviceChannels, String type) { + CatalogEvent outEvent = new CatalogEvent(this); + List channels = new ArrayList<>(); + if (deviceChannels.size() > 1) { + // 数据去重 + Set gbIdSet = new HashSet<>(); + for (DeviceChannel deviceChannel : deviceChannels) { + if (!gbIdSet.contains(deviceChannel.getChannelId())) { + gbIdSet.add(deviceChannel.getChannelId()); + channels.add(deviceChannel); + } + } + }else { + channels = deviceChannels; + } + outEvent.setDeviceChannels(channels); + outEvent.setType(type); + outEvent.setPlatformId(platformId); + applicationEventPublisher.publishEvent(outEvent); + } + + + public void catalogEventPublishForStream(String platformId, List gbStreams, String type) { + CatalogEvent outEvent = new CatalogEvent(this); + outEvent.setGbStreams(gbStreams); + outEvent.setType(type); + outEvent.setPlatformId(platformId); + applicationEventPublisher.publishEvent(outEvent); + } + + + public void catalogEventPublishForStream(String platformId, GbStream gbStream, String type) { + List gbStreamList = new ArrayList<>(); + gbStreamList.add(gbStream); + catalogEventPublishForStream(platformId, gbStreamList, type); + } + + public void recordEndEventPush(RecordInfo recordInfo) { + RecordEndEvent outEvent = new RecordEndEvent(this); + outEvent.setRecordInfo(recordInfo); + applicationEventPublisher.publishEvent(outEvent); + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEvent.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEvent.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java old mode 100644 new mode 100755 index a5da0186..c46e38a9 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java @@ -1,139 +1,139 @@ -package com.genersoft.iot.vmp.gb28181.session; - -import com.genersoft.iot.vmp.common.InviteSessionType; -import com.genersoft.iot.vmp.common.VideoManagerConstants; -import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; -import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; -import com.genersoft.iot.vmp.utils.JsonUtil; -import com.genersoft.iot.vmp.utils.redis.RedisUtil; -import gov.nist.javax.sip.message.SIPResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Component; -import org.springframework.util.ObjectUtils; - -import java.util.ArrayList; -import java.util.List; - -/** - * 视频流session管理器,管理视频预览、预览回放的通信句柄 - */ -@Component -public class VideoStreamSessionManager { - - @Autowired - private UserSetting userSetting; - - @Autowired - private RedisTemplate redisTemplate; - - /** - * 添加一个点播/回放的事务信息 - * 后续可以通过流Id/callID - * @param deviceId 设备ID - * @param channelId 通道ID - * @param callId 一次请求的CallID - * @param stream 流名称 - * @param mediaServerId 所使用的流媒体ID - * @param response 回复 - */ - public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, InviteSessionType type){ - SsrcTransaction ssrcTransaction = new SsrcTransaction(); - ssrcTransaction.setDeviceId(deviceId); - ssrcTransaction.setChannelId(channelId); - ssrcTransaction.setStream(stream); - ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo(response)); - ssrcTransaction.setCallId(callId); - ssrcTransaction.setSsrc(ssrc); - ssrcTransaction.setMediaServerId(mediaServerId); - ssrcTransaction.setType(type); - - redisTemplate.opsForValue().set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() - + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction); - } - - public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){ - - if (ObjectUtils.isEmpty(deviceId)) { - deviceId ="*"; - } - if (ObjectUtils.isEmpty(channelId)) { - channelId ="*"; - } - if (ObjectUtils.isEmpty(callId)) { - callId ="*"; - } - if (ObjectUtils.isEmpty(stream)) { - stream ="*"; - } - String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; - List scanResult = RedisUtil.scan(redisTemplate, key); - if (scanResult.size() == 0) { - return null; - } - return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); - } - - public List getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){ - if (ObjectUtils.isEmpty(deviceId)) { - deviceId ="*"; - } - if (ObjectUtils.isEmpty(channelId)) { - channelId ="*"; - } - if (ObjectUtils.isEmpty(callId)) { - callId ="*"; - } - if (ObjectUtils.isEmpty(stream)) { - stream ="*"; - } - String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; - List scanResult = RedisUtil.scan(redisTemplate, key); - if (scanResult.size() == 0) { - return null; - } - List result = new ArrayList<>(); - for (Object keyObj : scanResult) { - result.add((SsrcTransaction)redisTemplate.opsForValue().get(keyObj)); - } - return result; - } - - public String getMediaServerId(String deviceId, String channelId, String stream){ - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); - if (ssrcTransaction == null) { - return null; - } - return ssrcTransaction.getMediaServerId(); - } - - public String getSSRC(String deviceId, String channelId, String stream){ - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); - if (ssrcTransaction == null) { - return null; - } - return ssrcTransaction.getSsrc(); - } - - public void remove(String deviceId, String channelId, String stream) { - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); - if (ssrcTransaction == null) { - return; - } - redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" - + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream()); - } - - - public List getAllSsrc() { - List ssrcTransactionKeys = RedisUtil.scan(redisTemplate, String.format("%s_*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetting.getServerId())); - List result= new ArrayList<>(); - for (Object ssrcTransactionKey : ssrcTransactionKeys) { - String key = (String) ssrcTransactionKey; - SsrcTransaction ssrcTransaction = JsonUtil.redisJsonToObject(redisTemplate, key, SsrcTransaction.class); - result.add(ssrcTransaction); - } - return result; - } -} +package com.genersoft.iot.vmp.gb28181.session; + +import com.genersoft.iot.vmp.common.InviteSessionType; +import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; +import com.genersoft.iot.vmp.utils.JsonUtil; +import com.genersoft.iot.vmp.utils.redis.RedisUtil; +import gov.nist.javax.sip.message.SIPResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * 视频流session管理器,管理视频预览、预览回放的通信句柄 + */ +@Component +public class VideoStreamSessionManager { + + @Autowired + private UserSetting userSetting; + + @Autowired + private RedisTemplate redisTemplate; + + /** + * 添加一个点播/回放的事务信息 + * 后续可以通过流Id/callID + * @param deviceId 设备ID + * @param channelId 通道ID + * @param callId 一次请求的CallID + * @param stream 流名称 + * @param mediaServerId 所使用的流媒体ID + * @param response 回复 + */ + public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, InviteSessionType type){ + SsrcTransaction ssrcTransaction = new SsrcTransaction(); + ssrcTransaction.setDeviceId(deviceId); + ssrcTransaction.setChannelId(channelId); + ssrcTransaction.setStream(stream); + ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo(response)); + ssrcTransaction.setCallId(callId); + ssrcTransaction.setSsrc(ssrc); + ssrcTransaction.setMediaServerId(mediaServerId); + ssrcTransaction.setType(type); + + redisTemplate.opsForValue().set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction); + } + + public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){ + + if (ObjectUtils.isEmpty(deviceId)) { + deviceId ="*"; + } + if (ObjectUtils.isEmpty(channelId)) { + channelId ="*"; + } + if (ObjectUtils.isEmpty(callId)) { + callId ="*"; + } + if (ObjectUtils.isEmpty(stream)) { + stream ="*"; + } + String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; + List scanResult = RedisUtil.scan(redisTemplate, key); + if (scanResult.size() == 0) { + return null; + } + return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); + } + + public List getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){ + if (ObjectUtils.isEmpty(deviceId)) { + deviceId ="*"; + } + if (ObjectUtils.isEmpty(channelId)) { + channelId ="*"; + } + if (ObjectUtils.isEmpty(callId)) { + callId ="*"; + } + if (ObjectUtils.isEmpty(stream)) { + stream ="*"; + } + String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; + List scanResult = RedisUtil.scan(redisTemplate, key); + if (scanResult.size() == 0) { + return null; + } + List result = new ArrayList<>(); + for (Object keyObj : scanResult) { + result.add((SsrcTransaction)redisTemplate.opsForValue().get(keyObj)); + } + return result; + } + + public String getMediaServerId(String deviceId, String channelId, String stream){ + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); + if (ssrcTransaction == null) { + return null; + } + return ssrcTransaction.getMediaServerId(); + } + + public String getSSRC(String deviceId, String channelId, String stream){ + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); + if (ssrcTransaction == null) { + return null; + } + return ssrcTransaction.getSsrc(); + } + + public void remove(String deviceId, String channelId, String stream) { + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); + if (ssrcTransaction == null) { + return; + } + redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream()); + } + + + public List getAllSsrc() { + List ssrcTransactionKeys = RedisUtil.scan(redisTemplate, String.format("%s_*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetting.getServerId())); + List result= new ArrayList<>(); + for (Object ssrcTransactionKey : ssrcTransactionKeys) { + String key = (String) ssrcTransactionKey; + SsrcTransaction ssrcTransaction = JsonUtil.redisJsonToObject(redisTemplate, key, SsrcTransaction.class); + result.add(ssrcTransaction); + } + return result; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java old mode 100644 new mode 100755 index 8a621828..8d0ed7fb --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java @@ -1,160 +1,160 @@ -package com.genersoft.iot.vmp.gb28181.transmit.callback; - -import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx; -import org.springframework.stereotype.Component; -import org.springframework.util.ObjectUtils; -import org.springframework.web.context.request.async.DeferredResult; - -import java.util.Collection; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -/** - * @description: 异步请求处理 - * @author: swwheihei - * @date: 2020年5月8日 下午7:59:05 - */ -@SuppressWarnings(value = {"rawtypes", "unchecked"}) -@Component -public class DeferredResultHolder { - - public static final String CALLBACK_CMD_DEVICESTATUS = "CALLBACK_DEVICESTATUS"; - - public static final String CALLBACK_CMD_DEVICEINFO = "CALLBACK_DEVICEINFO"; - - public static final String CALLBACK_CMD_DEVICECONTROL = "CALLBACK_DEVICECONTROL"; - - public static final String CALLBACK_CMD_DEVICECONFIG = "CALLBACK_DEVICECONFIG"; - - public static final String CALLBACK_CMD_CONFIGDOWNLOAD = "CALLBACK_CONFIGDOWNLOAD"; - - public static final String CALLBACK_CMD_CATALOG = "CALLBACK_CATALOG"; - - public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO"; - - public static final String CALLBACK_CMD_PLAY = "CALLBACK_PLAY"; - - public static final String CALLBACK_CMD_PLAYBACK = "CALLBACK_PLAYBACK"; - - public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD"; - - public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY"; - - public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; - - public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL"; - - public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION"; - - public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY"; - - public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM"; - - public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST"; - - public static final String CALLBACK_CMD_SNAP= "CALLBACK_SNAP"; - - private Map> map = new ConcurrentHashMap<>(); - - - public void put(String key, String id, DeferredResultEx result) { - Map deferredResultMap = map.get(key); - if (deferredResultMap == null) { - deferredResultMap = new ConcurrentHashMap<>(); - map.put(key, deferredResultMap); - } - deferredResultMap.put(id, result); - } - - public void put(String key, String id, DeferredResult result) { - Map deferredResultMap = map.get(key); - if (deferredResultMap == null) { - deferredResultMap = new ConcurrentHashMap<>(); - map.put(key, deferredResultMap); - } - deferredResultMap.put(id, new DeferredResultEx(result)); - } - - public DeferredResultEx get(String key, String id) { - Map deferredResultMap = map.get(key); - if (deferredResultMap == null || ObjectUtils.isEmpty(id)) { - return null; - } - return deferredResultMap.get(id); - } - - public Collection getAllByKey(String key) { - Map deferredResultMap = map.get(key); - if (deferredResultMap == null) { - return null; - } - return deferredResultMap.values(); - } - - public boolean exist(String key, String id){ - if (key == null) { - return false; - } - Map deferredResultMap = map.get(key); - if (id == null) { - return deferredResultMap != null; - }else { - return deferredResultMap != null && deferredResultMap.get(id) != null; - } - } - - /** - * 释放单个请求 - * @param msg - */ - public void invokeResult(RequestMessage msg) { - Map deferredResultMap = map.get(msg.getKey()); - if (deferredResultMap == null) { - return; - } - DeferredResultEx result = deferredResultMap.get(msg.getId()); - if (result == null) { - return; - } - result.getDeferredResult().setResult(msg.getData()); - deferredResultMap.remove(msg.getId()); - if (deferredResultMap.size() == 0) { - map.remove(msg.getKey()); - } - } - - /** - * 释放所有的请求 - * @param msg - */ - public void invokeAllResult(RequestMessage msg) { - Map deferredResultMap = map.get(msg.getKey()); - if (deferredResultMap == null) { - return; - } - synchronized (this) { - deferredResultMap = map.get(msg.getKey()); - if (deferredResultMap == null) { - return; - } - Set ids = deferredResultMap.keySet(); - for (String id : ids) { - DeferredResultEx result = deferredResultMap.get(id); - if (result == null) { - return; - } - if (result.getFilter() != null) { - Object handler = result.getFilter().handler(msg.getData()); - result.getDeferredResult().setResult(handler); - }else { - result.getDeferredResult().setResult(msg.getData()); - } - - } - map.remove(msg.getKey()); - } - } - - -} +package com.genersoft.iot.vmp.gb28181.transmit.callback; + +import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import org.springframework.web.context.request.async.DeferredResult; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @description: 异步请求处理 + * @author: swwheihei + * @date: 2020年5月8日 下午7:59:05 + */ +@SuppressWarnings(value = {"rawtypes", "unchecked"}) +@Component +public class DeferredResultHolder { + + public static final String CALLBACK_CMD_DEVICESTATUS = "CALLBACK_DEVICESTATUS"; + + public static final String CALLBACK_CMD_DEVICEINFO = "CALLBACK_DEVICEINFO"; + + public static final String CALLBACK_CMD_DEVICECONTROL = "CALLBACK_DEVICECONTROL"; + + public static final String CALLBACK_CMD_DEVICECONFIG = "CALLBACK_DEVICECONFIG"; + + public static final String CALLBACK_CMD_CONFIGDOWNLOAD = "CALLBACK_CONFIGDOWNLOAD"; + + public static final String CALLBACK_CMD_CATALOG = "CALLBACK_CATALOG"; + + public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO"; + + public static final String CALLBACK_CMD_PLAY = "CALLBACK_PLAY"; + + public static final String CALLBACK_CMD_PLAYBACK = "CALLBACK_PLAYBACK"; + + public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD"; + + public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY"; + + public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; + + public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL"; + + public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION"; + + public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY"; + + public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM"; + + public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST"; + + public static final String CALLBACK_CMD_SNAP= "CALLBACK_SNAP"; + + private Map> map = new ConcurrentHashMap<>(); + + + public void put(String key, String id, DeferredResultEx result) { + Map deferredResultMap = map.get(key); + if (deferredResultMap == null) { + deferredResultMap = new ConcurrentHashMap<>(); + map.put(key, deferredResultMap); + } + deferredResultMap.put(id, result); + } + + public void put(String key, String id, DeferredResult result) { + Map deferredResultMap = map.get(key); + if (deferredResultMap == null) { + deferredResultMap = new ConcurrentHashMap<>(); + map.put(key, deferredResultMap); + } + deferredResultMap.put(id, new DeferredResultEx(result)); + } + + public DeferredResultEx get(String key, String id) { + Map deferredResultMap = map.get(key); + if (deferredResultMap == null || ObjectUtils.isEmpty(id)) { + return null; + } + return deferredResultMap.get(id); + } + + public Collection getAllByKey(String key) { + Map deferredResultMap = map.get(key); + if (deferredResultMap == null) { + return null; + } + return deferredResultMap.values(); + } + + public boolean exist(String key, String id){ + if (key == null) { + return false; + } + Map deferredResultMap = map.get(key); + if (id == null) { + return deferredResultMap != null; + }else { + return deferredResultMap != null && deferredResultMap.get(id) != null; + } + } + + /** + * 释放单个请求 + * @param msg + */ + public void invokeResult(RequestMessage msg) { + Map deferredResultMap = map.get(msg.getKey()); + if (deferredResultMap == null) { + return; + } + DeferredResultEx result = deferredResultMap.get(msg.getId()); + if (result == null) { + return; + } + result.getDeferredResult().setResult(msg.getData()); + deferredResultMap.remove(msg.getId()); + if (deferredResultMap.size() == 0) { + map.remove(msg.getKey()); + } + } + + /** + * 释放所有的请求 + * @param msg + */ + public void invokeAllResult(RequestMessage msg) { + Map deferredResultMap = map.get(msg.getKey()); + if (deferredResultMap == null) { + return; + } + synchronized (this) { + deferredResultMap = map.get(msg.getKey()); + if (deferredResultMap == null) { + return; + } + Set ids = deferredResultMap.keySet(); + for (String id : ids) { + DeferredResultEx result = deferredResultMap.get(id); + if (result == null) { + return; + } + if (result.getFilter() != null) { + Object handler = result.getFilter().handler(msg.getData()); + result.getDeferredResult().setResult(handler); + }else { + result.getDeferredResult().setResult(msg.getData()); + } + + } + map.remove(msg.getKey()); + } + } + + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java old mode 100644 new mode 100755 index 42ae577a..f4e2d201 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java @@ -1,39 +1,39 @@ -package com.genersoft.iot.vmp.gb28181.transmit.callback; - -/** - * @description: 请求信息定义 - * @author: swwheihei - * @date: 2020年5月8日 下午1:09:18 - */ -public class RequestMessage { - - private String id; - - private String key; - - private Object data; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public void setKey(String key) { - this.key = key; - } - - public String getKey() { - return key; - } - - public Object getData() { - return data; - } - - public void setData(Object data) { - this.data = data; - } -} +package com.genersoft.iot.vmp.gb28181.transmit.callback; + +/** + * @description: 请求信息定义 + * @author: swwheihei + * @date: 2020年5月8日 下午1:09:18 + */ +public class RequestMessage { + + private String id; + + private String key; + + private Object data; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public void setKey(String key) { + this.key = key; + } + + public String getKey() { + return key; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java old mode 100644 new mode 100755 index cff3b31d..a169a317 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java @@ -1,364 +1,364 @@ -package com.genersoft.iot.vmp.gb28181.transmit.cmd; - -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; -import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; -import com.genersoft.iot.vmp.service.bean.SSRCInfo; -import gov.nist.javax.sip.message.SIPRequest; - -import javax.sip.InvalidArgumentException; -import javax.sip.SipException; -import java.text.ParseException; - -/** - * @description:设备能力接口,用于定义设备的控制、查询能力 - * @author: swwheihei - * @date: 2020年5月3日 下午9:16:34 - */ -public interface ISIPCommander { - - /** - * 云台方向放控制,使用配置文件中的默认镜头移动速度 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - */ - void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException; - - /** - * 云台方向放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - * @param moveSpeed 镜头移动速度 - */ - void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; - - /** - * 云台缩放控制,使用配置文件中的默认镜头缩放速度 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - */ - void ptzZoomCmd(Device device,String channelId,int inOut) throws InvalidArgumentException, ParseException, SipException; - - /** - * 云台缩放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - */ - void ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; - - /** - * 云台控制,支持方向与缩放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - * @param moveSpeed 镜头移动速度 - * @param zoomSpeed 镜头缩放速度 - */ - void ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) throws InvalidArgumentException, SipException, ParseException; - - /** - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param cmdCode 指令码 - * @param parameter1 数据1 - * @param parameter2 数据2 - * @param combineCode2 组合码2 - */ - void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException; - - /** - * 前端控制指令(用于转发上级指令) - * @param device 控制设备 - * @param channelId 预览通道 - * @param cmdString 前端控制指令串 - */ - void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 请求预览视频流 - * @param device 视频设备 - * @param channelId 预览通道 - */ - void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 请求回放视频流 - * - * @param device 视频设备 - * @param channelId 预览通道 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss - */ - void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 请求历史媒体下载 - * - * @param device 视频设备 - * @param channelId 预览通道 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param downloadSpeed 下载倍速参数 - */ - void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, - String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent, - SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 视频流停止 - */ - void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; - - void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException; - - /** - * 回放暂停 - */ - void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException; - - /** - * 回放恢复 - */ - void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException; - - /** - * 回放拖动播放 - */ - void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException; - - /** - * 回放倍速播放 - */ - void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException; - - /** - * 回放控制 - * @param device - * @param streamInfo - * @param content - */ - void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException; - - - /** - * 语音广播 - * - * @param device 视频设备 - * @param channelId 预览通道 - */ - void audioBroadcastCmd(Device device,String channelId); - - /** - * 语音广播 - * - * @param device 视频设备 - */ - void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; - void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException; - - /** - * 音视频录像控制 - * - * @param device 视频设备 - * @param channelId 预览通道 - * @param recordCmdStr 录像命令:Record / StopRecord - */ - void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 远程启动控制命令 - * - * @param device 视频设备 - */ - void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException; - - /** - * 报警布防/撤防命令 - * - * @param device 视频设备 - */ - void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 报警复位命令 - * - * @param device 视频设备 - * @param alarmMethod 报警方式(可选) - * @param alarmType 报警类型(可选) - */ - void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 - * - * @param device 视频设备 - * @param channelId 预览通道 - */ - void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException; - - /** - * 看守位控制命令 - * - * @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; - - /** - * 设备配置命令 - * - * @param device 视频设备 - */ - void deviceConfigCmd(Device device); - - /** - * 设备配置命令:basicParam - * - * @param device 视频设备 - * @param channelId 通道编码(可选) - * @param name 设备/通道名称(可选) - * @param expiration 注册过期时间(可选) - * @param heartBeatInterval 心跳间隔时间(可选) - * @param heartBeatCount 心跳超时次数(可选) - */ - void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 查询设备状态 - * - * @param device 视频设备 - */ - void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 查询设备信息 - * - * @param device 视频设备 - * @return - */ - void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException; - - /** - * 查询目录列表 - * - * @param device 视频设备 - */ - void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException; - - /** - * 查询录像信息 - * - * @param device 视频设备 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param sn - */ - void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 查询报警信息 - * - * @param device 视频设备 - * @param startPriority 报警起始级别(可选) - * @param endPriority 报警终止级别(可选) - * @param alarmMethod 报警方式条件(可选) - * @param alarmType 报警类型 - * @param startTime 报警发生起始时间(可选) - * @param endTime 报警发生终止时间(可选) - * @return true = 命令发送成功 - */ - void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, - String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 查询设备配置 - * - * @param device 视频设备 - * @param channelId 通道编码(可选) - * @param configType 配置类型: - */ - void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 查询设备预置位置 - * - * @param device 视频设备 - */ - void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 查询移动设备位置数据 - * - * @param device 视频设备 - */ - void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 订阅、取消订阅移动位置 - * - * @param device 视频设备 - * @return true = 命令发送成功 - */ - SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 订阅、取消订阅报警信息 - * @param device 视频设备 - * @param expires 订阅过期时间(0 = 取消订阅) - * @param startPriority 报警起始级别(可选) - * @param endPriority 报警终止级别(可选) - * @param alarmType 报警类型 - * @param startTime 报警发生起始时间(可选) - * @param endTime 报警发生终止时间(可选) - * @return true = 命令发送成功 - */ - void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException; - - /** - * 订阅、取消订阅目录信息 - * @param device 视频设备 - * @return true = 命令发送成功 - */ - SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - - /** - * 拉框控制命令 - * - * @param device 控制设备 - * @param channelId 通道id - * @param cmdString 前端控制指令串 - */ - void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException; - - - /** - * 向设备发送报警NOTIFY消息, 用于互联结构下,此时将设备当成一个平级平台看待 - * @param device 设备 - * @param deviceAlarm 报警信息信息 - * @return - */ - void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException; - -} +package com.genersoft.iot.vmp.gb28181.transmit.cmd; + +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; +import com.genersoft.iot.vmp.service.bean.SSRCInfo; +import gov.nist.javax.sip.message.SIPRequest; + +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; + +/** + * @description:设备能力接口,用于定义设备的控制、查询能力 + * @author: swwheihei + * @date: 2020年5月3日 下午9:16:34 + */ +public interface ISIPCommander { + + /** + * 云台方向放控制,使用配置文件中的默认镜头移动速度 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 + */ + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException; + + /** + * 云台方向放控制 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 + * @param moveSpeed 镜头移动速度 + */ + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; + + /** + * 云台缩放控制,使用配置文件中的默认镜头缩放速度 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 + */ + void ptzZoomCmd(Device device,String channelId,int inOut) throws InvalidArgumentException, ParseException, SipException; + + /** + * 云台缩放控制 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 + */ + void ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; + + /** + * 云台控制,支持方向与缩放控制 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 + * @param moveSpeed 镜头移动速度 + * @param zoomSpeed 镜头缩放速度 + */ + void ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) throws InvalidArgumentException, SipException, ParseException; + + /** + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param cmdCode 指令码 + * @param parameter1 数据1 + * @param parameter2 数据2 + * @param combineCode2 组合码2 + */ + void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException; + + /** + * 前端控制指令(用于转发上级指令) + * @param device 控制设备 + * @param channelId 预览通道 + * @param cmdString 前端控制指令串 + */ + void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 请求预览视频流 + * @param device 视频设备 + * @param channelId 预览通道 + */ + void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 请求回放视频流 + * + * @param device 视频设备 + * @param channelId 预览通道 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss + */ + void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 请求历史媒体下载 + * + * @param device 视频设备 + * @param channelId 预览通道 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param downloadSpeed 下载倍速参数 + */ + void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, + String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent, + SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 视频流停止 + */ + void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; + + void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException; + + /** + * 回放暂停 + */ + void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException; + + /** + * 回放恢复 + */ + void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException; + + /** + * 回放拖动播放 + */ + void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException; + + /** + * 回放倍速播放 + */ + void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException; + + /** + * 回放控制 + * @param device + * @param streamInfo + * @param content + */ + void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException; + + + /** + * 语音广播 + * + * @param device 视频设备 + * @param channelId 预览通道 + */ + void audioBroadcastCmd(Device device,String channelId); + + /** + * 语音广播 + * + * @param device 视频设备 + */ + void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; + void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException; + + /** + * 音视频录像控制 + * + * @param device 视频设备 + * @param channelId 预览通道 + * @param recordCmdStr 录像命令:Record / StopRecord + */ + void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 远程启动控制命令 + * + * @param device 视频设备 + */ + void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException; + + /** + * 报警布防/撤防命令 + * + * @param device 视频设备 + */ + void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 报警复位命令 + * + * @param device 视频设备 + * @param alarmMethod 报警方式(可选) + * @param alarmType 报警类型(可选) + */ + void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 + * + * @param device 视频设备 + * @param channelId 预览通道 + */ + void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException; + + /** + * 看守位控制命令 + * + * @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; + + /** + * 设备配置命令 + * + * @param device 视频设备 + */ + void deviceConfigCmd(Device device); + + /** + * 设备配置命令:basicParam + * + * @param device 视频设备 + * @param channelId 通道编码(可选) + * @param name 设备/通道名称(可选) + * @param expiration 注册过期时间(可选) + * @param heartBeatInterval 心跳间隔时间(可选) + * @param heartBeatCount 心跳超时次数(可选) + */ + void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 查询设备状态 + * + * @param device 视频设备 + */ + void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 查询设备信息 + * + * @param device 视频设备 + * @return + */ + void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException; + + /** + * 查询目录列表 + * + * @param device 视频设备 + */ + void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException; + + /** + * 查询录像信息 + * + * @param device 视频设备 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param sn + */ + void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 查询报警信息 + * + * @param device 视频设备 + * @param startPriority 报警起始级别(可选) + * @param endPriority 报警终止级别(可选) + * @param alarmMethod 报警方式条件(可选) + * @param alarmType 报警类型 + * @param startTime 报警发生起始时间(可选) + * @param endTime 报警发生终止时间(可选) + * @return true = 命令发送成功 + */ + void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, + String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 查询设备配置 + * + * @param device 视频设备 + * @param channelId 通道编码(可选) + * @param configType 配置类型: + */ + void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 查询设备预置位置 + * + * @param device 视频设备 + */ + void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 查询移动设备位置数据 + * + * @param device 视频设备 + */ + void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 订阅、取消订阅移动位置 + * + * @param device 视频设备 + * @return true = 命令发送成功 + */ + SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 订阅、取消订阅报警信息 + * @param device 视频设备 + * @param expires 订阅过期时间(0 = 取消订阅) + * @param startPriority 报警起始级别(可选) + * @param endPriority 报警终止级别(可选) + * @param alarmType 报警类型 + * @param startTime 报警发生起始时间(可选) + * @param endTime 报警发生终止时间(可选) + * @return true = 命令发送成功 + */ + void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException; + + /** + * 订阅、取消订阅目录信息 + * @param device 视频设备 + * @return true = 命令发送成功 + */ + SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + + /** + * 拉框控制命令 + * + * @param device 控制设备 + * @param channelId 通道id + * @param cmdString 前端控制指令串 + */ + void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException; + + + /** + * 向设备发送报警NOTIFY消息, 用于互联结构下,此时将设备当成一个平级平台看待 + * @param device 设备 + * @param deviceAlarm 报警信息信息 + * @return + */ + void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException; + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java old mode 100644 new mode 100755 index 89964370..88f5f1a6 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java @@ -1,318 +1,318 @@ -package com.genersoft.iot.vmp.gb28181.transmit.cmd; - -import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.SipLayer; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; -import com.genersoft.iot.vmp.gb28181.utils.SipUtils; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.utils.GitUtil; -import gov.nist.javax.sip.message.SIPRequest; -import gov.nist.javax.sip.message.SIPResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.sip.InvalidArgumentException; -import javax.sip.PeerUnavailableException; -import javax.sip.SipException; -import javax.sip.SipFactory; -import javax.sip.address.Address; -import javax.sip.address.SipURI; -import javax.sip.header.*; -import javax.sip.message.Request; -import java.text.ParseException; -import java.util.ArrayList; - -/** - * @description:摄像头命令request创造器 TODO 冗余代码太多待优化 - * @author: swwheihei - * @date: 2020年5月6日 上午9:29:02 - */ -@Component -public class SIPRequestHeaderProvider { - - @Autowired - private SipConfig sipConfig; - - @Autowired - private SipLayer sipLayer; - - @Autowired - private GitUtil gitUtil; - - @Autowired - private IRedisCatchStorage redisCatchStorage; - - @Autowired - private VideoStreamSessionManager streamSession; - - public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { - Request request = null; - // sipuri - SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); - // via - ArrayList viaHeaders = new ArrayList(); - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); - viaHeader.setRPort(); - viaHeaders.add(viaHeader); - // from - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); - // to - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag); - - // Forwards - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); - // ceq - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE); - - request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, - toHeader, viaHeaders, maxForwards); - - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); - - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); - request.setContent(content, contentTypeHeader); - return request; - } - - public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { - Request request = null; - //请求行 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); - //via - ArrayList viaHeaders = new ArrayList(); - HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory(); - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); - viaHeader.setRPort(); - viaHeaders.add(viaHeader); - - //from - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack - //to - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null); - - //Forwards - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); - - //ceq - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); - - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); - - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); - // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort())); - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); - // Subject - SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0)); - request.addHeader(subjectHeader); - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); - request.setContent(content, contentTypeHeader); - return request; - } - - public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException { - Request request = null; - //请求行 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); - // via - ArrayList viaHeaders = new ArrayList(); - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); - viaHeader.setRPort(); - viaHeaders.add(viaHeader); - //from - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack - //to - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null); - - //Forwards - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); - - //ceq - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); - - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); - // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort())); - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); - - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); - - // Subject - SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0)); - request.addHeader(subjectHeader); - - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); - request.setContent(content, contentTypeHeader); - return request; - } - - public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException { - Request request = null; - //请求行 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); - // via - ArrayList viaHeaders = new ArrayList(); - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); - viaHeaders.add(viaHeader); - //from - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain()); - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); - //to - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress()); - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); - - //Forwards - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); - - //ceq - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE); - CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId()); - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); - - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); - - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); - - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); - - return request; - } - - public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { - Request request = null; - // sipuri - SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); - // via - ArrayList viaHeaders = new ArrayList(); - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), - device.getTransport(), SipUtils.getNewViaTag()); - viaHeader.setRPort(); - viaHeaders.add(viaHeader); - // from - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag()); - // to - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, requestOld == null ? null :requestOld.getToTag()); - - // Forwards - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); - - // ceq - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.SUBSCRIBE); - - request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader, - toHeader, viaHeaders, maxForwards); - - - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); - - // Expires - ExpiresHeader expireHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(expires); - request.addHeader(expireHeader); - - // Event - EventHeader eventHeader = SipFactory.getInstance().createHeaderFactory().createEventHeader(event); - - int random = (int) Math.floor(Math.random() * 10000); - eventHeader.setEventId(random + ""); - request.addHeader(eventHeader); - - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); - request.setContent(content, contentTypeHeader); - - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); - - return request; - } - - public SIPRequest createInfoRequest(Device device, String channelId, String content, SipTransactionInfo transactionInfo) - throws SipException, ParseException, InvalidArgumentException { - if (device == null || transactionInfo == null) { - return null; - } - SIPRequest request = null; - //请求行 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); - // via - ArrayList viaHeaders = new ArrayList(); - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); - viaHeaders.add(viaHeader); - //from - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain()); - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); - //to - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress()); - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); - - //Forwards - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); - - //ceq - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO); - CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId()); - request = (SIPRequest)SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); - - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); - - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); - - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); - - if (content != null) { - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", - "MANSRTSP"); - request.setContent(content, contentTypeHeader); - } - return request; - } - - public Request createAckRequest(String localIp, SipURI sipURI, SIPResponse sipResponse) throws ParseException, InvalidArgumentException, PeerUnavailableException { - - - // via - ArrayList viaHeaders = new ArrayList(); - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(localIp, sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag()); - viaHeaders.add(viaHeader); - - //Forwards - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); - - //ceq - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK); - - Request request = SipFactory.getInstance().createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards); - - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); - - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), localIp + ":"+sipConfig.getPort())); - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); - - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); - - return request; - } -} +package com.genersoft.iot.vmp.gb28181.transmit.cmd; + +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.gb28181.SipLayer; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import com.genersoft.iot.vmp.utils.GitUtil; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.PeerUnavailableException; +import javax.sip.SipException; +import javax.sip.SipFactory; +import javax.sip.address.Address; +import javax.sip.address.SipURI; +import javax.sip.header.*; +import javax.sip.message.Request; +import java.text.ParseException; +import java.util.ArrayList; + +/** + * @description:摄像头命令request创造器 TODO 冗余代码太多待优化 + * @author: swwheihei + * @date: 2020年5月6日 上午9:29:02 + */ +@Component +public class SIPRequestHeaderProvider { + + @Autowired + private SipConfig sipConfig; + + @Autowired + private SipLayer sipLayer; + + @Autowired + private GitUtil gitUtil; + + @Autowired + private IRedisCatchStorage redisCatchStorage; + + @Autowired + private VideoStreamSessionManager streamSession; + + public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { + Request request = null; + // sipuri + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); + // via + ArrayList viaHeaders = new ArrayList(); + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); + viaHeader.setRPort(); + viaHeaders.add(viaHeader); + // from + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); + // to + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag); + + // Forwards + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); + // ceq + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE); + + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, + toHeader, viaHeaders, maxForwards); + + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); + + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); + request.setContent(content, contentTypeHeader); + return request; + } + + public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { + Request request = null; + //请求行 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); + //via + ArrayList viaHeaders = new ArrayList(); + HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory(); + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); + viaHeader.setRPort(); + viaHeaders.add(viaHeader); + + //from + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack + //to + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null); + + //Forwards + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); + + //ceq + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); + + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); + + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); + // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort())); + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); + // Subject + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0)); + request.addHeader(subjectHeader); + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); + request.setContent(content, contentTypeHeader); + return request; + } + + public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException { + Request request = null; + //请求行 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); + // via + ArrayList viaHeaders = new ArrayList(); + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); + viaHeader.setRPort(); + viaHeaders.add(viaHeader); + //from + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack + //to + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null); + + //Forwards + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); + + //ceq + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); + + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); + // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort())); + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); + + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); + + // Subject + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0)); + request.addHeader(subjectHeader); + + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); + request.setContent(content, contentTypeHeader); + return request; + } + + public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException { + Request request = null; + //请求行 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); + // via + ArrayList viaHeaders = new ArrayList(); + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); + viaHeaders.add(viaHeader); + //from + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain()); + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); + //to + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress()); + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); + + //Forwards + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); + + //ceq + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE); + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId()); + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); + + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); + + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); + + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); + + return request; + } + + public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { + Request request = null; + // sipuri + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); + // via + ArrayList viaHeaders = new ArrayList(); + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), + device.getTransport(), SipUtils.getNewViaTag()); + viaHeader.setRPort(); + viaHeaders.add(viaHeader); + // from + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag()); + // to + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, requestOld == null ? null :requestOld.getToTag()); + + // Forwards + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); + + // ceq + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.SUBSCRIBE); + + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader, + toHeader, viaHeaders, maxForwards); + + + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); + + // Expires + ExpiresHeader expireHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(expires); + request.addHeader(expireHeader); + + // Event + EventHeader eventHeader = SipFactory.getInstance().createHeaderFactory().createEventHeader(event); + + int random = (int) Math.floor(Math.random() * 10000); + eventHeader.setEventId(random + ""); + request.addHeader(eventHeader); + + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); + request.setContent(content, contentTypeHeader); + + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); + + return request; + } + + public SIPRequest createInfoRequest(Device device, String channelId, String content, SipTransactionInfo transactionInfo) + throws SipException, ParseException, InvalidArgumentException { + if (device == null || transactionInfo == null) { + return null; + } + SIPRequest request = null; + //请求行 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); + // via + ArrayList viaHeaders = new ArrayList(); + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); + viaHeaders.add(viaHeader); + //from + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain()); + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); + //to + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress()); + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); + + //Forwards + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); + + //ceq + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO); + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId()); + request = (SIPRequest)SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); + + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); + + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); + + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); + + if (content != null) { + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", + "MANSRTSP"); + request.setContent(content, contentTypeHeader); + } + return request; + } + + public Request createAckRequest(String localIp, SipURI sipURI, SIPResponse sipResponse) throws ParseException, InvalidArgumentException, PeerUnavailableException { + + + // via + ArrayList viaHeaders = new ArrayList(); + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(localIp, sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag()); + viaHeaders.add(viaHeader); + + //Forwards + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); + + //ceq + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK); + + Request request = SipFactory.getInstance().createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards); + + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); + + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), localIp + ":"+sipConfig.getPort())); + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); + + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); + + return request; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java old mode 100644 new mode 100755 index dd46544b..b82bb71e --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -1,1424 +1,1424 @@ -package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; - -import com.genersoft.iot.vmp.common.InviteSessionType; -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; -import com.genersoft.iot.vmp.gb28181.SipLayer; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; -import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; -import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; -import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; -import com.genersoft.iot.vmp.gb28181.utils.SipUtils; -import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; -import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; -import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; -import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; -import com.genersoft.iot.vmp.service.IMediaServerService; -import com.genersoft.iot.vmp.service.bean.SSRCInfo; -import com.genersoft.iot.vmp.utils.DateUtil; -import gov.nist.javax.sip.message.SIPRequest; -import gov.nist.javax.sip.message.SIPResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.DependsOn; -import org.springframework.stereotype.Component; -import org.springframework.util.ObjectUtils; - -import javax.sip.InvalidArgumentException; -import javax.sip.ResponseEvent; -import javax.sip.SipException; -import javax.sip.SipFactory; -import javax.sip.header.CallIdHeader; -import javax.sip.message.Request; -import java.text.ParseException; - -/** - * @description:设备能力接口,用于定义设备的控制、查询能力 - * @author: swwheihei - * @date: 2020年5月3日 下午9:22:48 - */ -@Component -@DependsOn("sipLayer") -public class SIPCommander implements ISIPCommander { - - private final Logger logger = LoggerFactory.getLogger(SIPCommander.class); - - @Autowired - private SipConfig sipConfig; - - @Autowired - private SipLayer sipLayer; - - @Autowired - private SIPSender sipSender; - - @Autowired - private SIPRequestHeaderProvider headerProvider; - - @Autowired - private VideoStreamSessionManager streamSession; - - @Autowired - private UserSetting userSetting; - - @Autowired - private ZlmHttpHookSubscribe subscribe; - - - - @Autowired - private IMediaServerService mediaServerService; - - - /** - * 云台方向放控制,使用配置文件中的默认镜头移动速度 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - */ - @Override - public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException { - ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0); - } - - /** - * 云台方向放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - * @param moveSpeed 镜头移动速度 - */ - @Override - public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException { - ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0); - } - - /** - * 云台缩放控制,使用配置文件中的默认镜头缩放速度 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - */ - @Override - public void ptzZoomCmd(Device device, String channelId, int inOut) throws InvalidArgumentException, ParseException, SipException { - ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed()); - } - - /** - * 云台缩放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - * @param zoomSpeed 镜头缩放速度 - */ - @Override - public void ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) throws InvalidArgumentException, ParseException, SipException { - ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed); - } - - /** - * 云台指令码计算 - * - * @param cmdCode 指令码 - * @param parameter1 数据1 - * @param parameter2 数据2 - * @param combineCode2 组合码2 - */ - public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) { - StringBuilder builder = new StringBuilder("A50F01"); - String strTmp; - strTmp = String.format("%02X", cmdCode); - builder.append(strTmp, 0, 2); - strTmp = String.format("%02X", parameter1); - builder.append(strTmp, 0, 2); - strTmp = String.format("%02X", parameter2); - builder.append(strTmp, 0, 2); - //优化zoom变倍速率 - if ((combineCode2 > 0) && (combineCode2 <16)) - { - combineCode2 = 16; - } - strTmp = String.format("%X", combineCode2); - builder.append(strTmp, 0, 1).append("0"); - //计算校验码 - int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100; - strTmp = String.format("%02X", checkCode); - builder.append(strTmp, 0, 2); - return builder.toString(); - } - - /** - * 云台控制,支持方向与缩放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - * @param moveSpeed 镜头移动速度 - * @param zoomSpeed 镜头缩放速度 - */ - @Override - public void ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed, - int zoomSpeed) throws InvalidArgumentException, SipException, ParseException { - String cmdStr = SipUtils.cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed); - StringBuilder ptzXml = new StringBuilder(200); - String charset = device.getCharset(); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("DeviceControl\r\n"); - ptzXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - ptzXml.append("" + channelId + "\r\n"); - ptzXml.append("" + cmdStr + "\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("5\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); - - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); - } - - /** - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param cmdCode 指令码 - * @param parameter1 数据1 - * @param parameter2 数据2 - * @param combineCode2 组合码2 - */ - @Override - public void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException { - - String cmdStr = frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2); - StringBuffer ptzXml = new StringBuffer(200); - String charset = device.getCharset(); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("DeviceControl\r\n"); - ptzXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - ptzXml.append("" + channelId + "\r\n"); - ptzXml.append("" + cmdStr + "\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("5\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); - - - - - SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); - - } - - /** - * 前端控制指令(用于转发上级指令) - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param cmdString 前端控制指令串 - */ - @Override - public void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer ptzXml = new StringBuffer(200); - String charset = device.getCharset(); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("DeviceControl\r\n"); - ptzXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - ptzXml.append("" + channelId + "\r\n"); - ptzXml.append("" + cmdString + "\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("5\r\n"); - ptzXml.append("\r\n"); - ptzXml.append("\r\n"); - - - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request, errorEvent, okEvent); - - } - - /** - * 请求预览视频流 - * - * @param device 视频设备 - * @param channelId 预览通道 - * @param event hook订阅 - * @param errorEvent sip错误订阅 - */ - @Override - public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, - ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - String stream = ssrcInfo.getStream(); - - if (device == null) { - return; - } - - logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> { - if (event != null) { - event.response(mediaServerItemInUse, hookParam); - subscribe.removeSubscribe(hookSubscribe); - } - }); - String sdpIp; - if (!ObjectUtils.isEmpty(device.getSdpIp())) { - sdpIp = device.getSdpIp(); - }else { - sdpIp = mediaServerItem.getSdpIp(); - } - StringBuffer content = new StringBuffer(200); - content.append("v=0\r\n"); - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); - content.append("s=Play\r\n"); - content.append("c=IN IP4 " + sdpIp + "\r\n"); - content.append("t=0 0\r\n"); - - if (userSetting.isSeniorSdp()) { - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:126 H264/90000\r\n"); - content.append("a=rtpmap:125 H264S/90000\r\n"); - content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:99 H265/90000\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - } else { - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); - } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) { - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - content.append("a=rtpmap:99 H265/90000\r\n"); - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - } - - if( device.isSwitchPrimarySubStream() ){ - if("TP-LINK".equals(device.getManufacturer())){ - if (device.isSwitchPrimarySubStream()){ - content.append("a=streamMode:sub\r\n"); - }else { - content.append("a=streamMode:main\r\n"); - } - }else { - if (device.isSwitchPrimarySubStream()){ - content.append("a=streamprofile:1\r\n"); - }else { - content.append("a=streamprofile:0\r\n"); - } - } - } - - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc - // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率 -// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备 - - - - Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> { - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); - errorEvent.response(e); - }), e -> { - ResponseEvent responseEvent = (ResponseEvent) e.event; - SIPResponse response = (SIPResponse) responseEvent.getResponse(); - streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, - InviteSessionType.PLAY); - okEvent.response(e); - }); - } - - /** - * 请求回放视频流 - * - * @param device 视频设备 - * @param channelId 预览通道 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss - */ - @Override - public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, - String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent, - SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - - - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); - String sdpIp; - if (!ObjectUtils.isEmpty(device.getSdpIp())) { - sdpIp = device.getSdpIp(); - }else { - sdpIp = mediaServerItem.getSdpIp(); - } - StringBuffer content = new StringBuffer(200); - content.append("v=0\r\n"); - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); - content.append("s=Playback\r\n"); - content.append("u=" + channelId + ":0\r\n"); - content.append("c=IN IP4 " + sdpIp + "\r\n"); - content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " " - + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n"); - - String streamMode = device.getStreamMode(); - - if (userSetting.isSeniorSdp()) { - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - } else if ("UDP".equalsIgnoreCase(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:126 H264/90000\r\n"); - content.append("a=rtpmap:125 H264S/90000\r\n"); - content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:99 H265/90000\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - } else { - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); - } else if ("UDP".equalsIgnoreCase(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:99 H265/90000\r\n"); - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { - // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { - // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - } - - //ssrc - content.append("y=" + ssrcInfo.getSsrc() + "\r\n"); - - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); - // 添加订阅 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> { - if (hookEvent != null) { - hookEvent.response(mediaServerItemInUse, hookParam); - } - subscribe.removeSubscribe(hookSubscribe); - }); - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc()); - - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { - ResponseEvent responseEvent = (ResponseEvent) event.event; - SIPResponse response = (SIPResponse) responseEvent.getResponse(); - streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK); - okEvent.response(event); - }); - } - - /** - * 请求历史媒体下载 - * - * @param device 视频设备 - * @param channelId 预览通道 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param downloadSpeed 下载倍速参数 - */ - @Override - public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, - String startTime, String endTime, int downloadSpeed, - ZlmHttpHookSubscribe.Event hookEvent, - SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { - - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); - String sdpIp; - if (!ObjectUtils.isEmpty(device.getSdpIp())) { - sdpIp = device.getSdpIp(); - }else { - sdpIp = mediaServerItem.getSdpIp(); - } - StringBuffer content = new StringBuffer(200); - content.append("v=0\r\n"); - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); - content.append("s=Download\r\n"); - content.append("u=" + channelId + ":0\r\n"); - content.append("c=IN IP4 " + sdpIp + "\r\n"); - content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " " - + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n"); - - String streamMode = device.getStreamMode().toUpperCase(); - - if (userSetting.isSeniorSdp()) { - if ("TCP-PASSIVE".equals(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - } else if ("TCP-ACTIVE".equals(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); - } else if ("UDP".equals(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:126 H264/90000\r\n"); - content.append("a=rtpmap:125 H264S/90000\r\n"); - content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:99 MP4V-ES/90000\r\n"); - content.append("a=fmtp:99 profile-level-id=3\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - } else { - if ("TCP-PASSIVE".equals(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); - } else if ("TCP-ACTIVE".equals(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); - } else if ("UDP".equals(streamMode)) { - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:99 H265/90000\r\n"); - if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); - } - } - content.append("a=downloadspeed:" + downloadSpeed + "\r\n"); - - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc - logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc()); - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); - // 添加订阅 - CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); - String callId= newCallIdHeader.getCallId(); - subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> { - logger.debug("sipc 添加订阅===callId {}",callId); - hookEvent.response(mediaServerItemInUse, hookParam); - subscribe.removeSubscribe(hookSubscribe); - hookSubscribe.getContent().put("regist", false); - hookSubscribe.getContent().put("schema", "rtsp"); - // 添加流注销的订阅,注销了后向设备发送bye - subscribe.addSubscribe(hookSubscribe, - (mediaServerItemForEnd, hookParam1) -> { - logger.info("[录像]下载结束, 发送BYE"); - try { - streamByeCmd(device, channelId, ssrcInfo.getStream(), callId); - } catch (InvalidArgumentException | ParseException | SipException | - SsrcTransactionNotFoundException e) { - logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage()); - } - }); - }); - - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc()); - - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { - ResponseEvent responseEvent = (ResponseEvent) event.event; - SIPResponse response = (SIPResponse) responseEvent.getResponse(); - String contentString =new String(response.getRawContent()); - String ssrc = SipUtils.getSsrcFromSdp(contentString); - streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD); - okEvent.response(event); - }); - } - - /** - * 视频流停止, 不使用回调 - */ - @Override - public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException { - streamByeCmd(device, channelId, stream, callId, null); - } - - /** - * 视频流停止 - */ - @Override - public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callId, stream); - if (ssrcTransaction == null) { - throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream); - } - - mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); - mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); - streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); - - Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo()); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent); - } - - /** - * 语音广播 - * - * @param device 视频设备 - * @param channelId 预览通道 - */ - @Override - public void audioBroadcastCmd(Device device, String channelId) { - } - - /** - * 语音广播 - * - * @param device 视频设备 - */ - @Override - public void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer broadcastXml = new StringBuffer(200); - String charset = device.getCharset(); - broadcastXml.append("\r\n"); - broadcastXml.append("\r\n"); - broadcastXml.append("Broadcast\r\n"); - broadcastXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - broadcastXml.append("" + sipConfig.getId() + "\r\n"); - broadcastXml.append("" + device.getDeviceId() + "\r\n"); - broadcastXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); - - } - - @Override - public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer broadcastXml = new StringBuffer(200); - String charset = device.getCharset(); - broadcastXml.append("\r\n"); - broadcastXml.append("\r\n"); - broadcastXml.append("Broadcast\r\n"); - broadcastXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - broadcastXml.append("" + sipConfig.getId() + "\r\n"); - broadcastXml.append("" + device.getDeviceId() + "\r\n"); - broadcastXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); - - } - - - /** - * 音视频录像控制 - * - * @param device 视频设备 - * @param channelId 预览通道 - * @param recordCmdStr 录像命令:Record / StopRecord - */ - @Override - public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("" + recordCmdStr + "\r\n"); - cmdXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); - } - - /** - * 远程启动控制命令 - * - * @param device 视频设备 - */ - @Override - public void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - cmdXml.append("Boot\r\n"); - cmdXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); - } - - /** - * 报警布防/撤防命令 - * - * @param device 视频设备 - * @param guardCmdStr "SetGuard"/"ResetGuard" - */ - @Override - public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - cmdXml.append("" + guardCmdStr + "\r\n"); - cmdXml.append("\r\n"); - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); - } - - /** - * 报警复位命令 - * - * @param device 视频设备 - */ - @Override - public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - cmdXml.append("ResetAlarm\r\n"); - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { - cmdXml.append("\r\n"); - } - if (!ObjectUtils.isEmpty(alarmMethod)) { - cmdXml.append("" + alarmMethod + "\r\n"); - } - if (!ObjectUtils.isEmpty(alarmType)) { - cmdXml.append("" + alarmType + "\r\n"); - } - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { - cmdXml.append("\r\n"); - } - cmdXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); - } - - /** - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 - * - * @param device 视频设备 - * @param channelId 预览通道 - */ - @Override - public void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("Send\r\n"); - cmdXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); - } - - /** - * 看守位控制命令 - * - * @param device 视频设备 - * @param channelId 通道id,非通道则是设备本身 - * @param enabled 看守位使能:1 = 开启,0 = 关闭 - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) - * @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 { - - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("\r\n"); - if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) { - cmdXml.append("1\r\n"); - if (NumericUtil.isInteger(resetTime)) { - cmdXml.append("" + resetTime + "\r\n"); - } else { - cmdXml.append("0\r\n"); - } - if (NumericUtil.isInteger(presetIndex)) { - cmdXml.append("" + presetIndex + "\r\n"); - } else { - cmdXml.append("0\r\n"); - } - } else { - cmdXml.append("0\r\n"); - } - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); - } - - /** - * 设备配置命令 - * - * @param device 视频设备 - */ - @Override - public void deviceConfigCmd(Device device) { - // TODO Auto-generated method stub - } - - /** - * 设备配置命令:basicParam - * - * @param device 视频设备 - * @param channelId 通道编码(可选) - * @param name 设备/通道名称(可选) - * @param expiration 注册过期时间(可选) - * @param heartBeatInterval 心跳间隔时间(可选) - * @param heartBeatCount 心跳超时次数(可选) - */ - @Override - public void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, - String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("DeviceConfig\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("\r\n"); - if (!ObjectUtils.isEmpty(name)) { - cmdXml.append("" + name + "\r\n"); - } - if (NumericUtil.isInteger(expiration)) { - if (Integer.valueOf(expiration) > 0) { - cmdXml.append("" + expiration + "\r\n"); - } - } - if (NumericUtil.isInteger(heartBeatInterval)) { - if (Integer.valueOf(heartBeatInterval) > 0) { - cmdXml.append("" + heartBeatInterval + "\r\n"); - } - } - if (NumericUtil.isInteger(heartBeatCount)) { - if (Integer.valueOf(heartBeatCount) > 0) { - cmdXml.append("" + heartBeatCount + "\r\n"); - } - } - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); - } - - /** - * 查询设备状态 - * - * @param device 视频设备 - */ - @Override - public void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - - String charset = device.getCharset(); - StringBuffer catalogXml = new StringBuffer(200); - catalogXml.append("\r\n"); - catalogXml.append("\r\n"); - catalogXml.append("DeviceStatus\r\n"); - catalogXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - catalogXml.append("" + device.getDeviceId() + "\r\n"); - catalogXml.append("\r\n"); - - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); - } - - /** - * 查询设备信息 - * - * @param device 视频设备 - */ - @Override - public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer catalogXml = new StringBuffer(200); - String charset = device.getCharset(); - catalogXml.append("\r\n"); - catalogXml.append("\r\n"); - catalogXml.append("DeviceInfo\r\n"); - catalogXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - catalogXml.append("" + device.getDeviceId() + "\r\n"); - catalogXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); - - } - - /** - * 查询目录列表 - * - * @param device 视频设备 - */ - @Override - public void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException { - - StringBuffer catalogXml = new StringBuffer(200); - String charset = device.getCharset(); - catalogXml.append("\r\n"); - catalogXml.append("\r\n"); - catalogXml.append(" Catalog\r\n"); - catalogXml.append(" " + sn + "\r\n"); - catalogXml.append(" " + device.getDeviceId() + "\r\n"); - catalogXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); - } - - /** - * 查询录像信息 - * - * @param device 视频设备 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss - */ - @Override - public void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - if (secrecy == null) { - secrecy = 0; - } - if (type == null) { - type = "all"; - } - - StringBuffer recordInfoXml = new StringBuffer(200); - String charset = device.getCharset(); - recordInfoXml.append("\r\n"); - recordInfoXml.append("\r\n"); - recordInfoXml.append("RecordInfo\r\n"); - recordInfoXml.append("" + sn + "\r\n"); - recordInfoXml.append("" + channelId + "\r\n"); - if (startTime != null) { - recordInfoXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "\r\n"); - } - if (endTime != null) { - recordInfoXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "\r\n"); - } - if (secrecy != null) { - recordInfoXml.append(" " + secrecy + " \r\n"); - } - if (type != null) { - // 大华NVR要求必须增加一个值为all的文本元素节点Type - recordInfoXml.append("" + type + "\r\n"); - } - recordInfoXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), - SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); - } - - /** - * 查询报警信息 - * - * @param device 视频设备 - * @param startPriority 报警起始级别(可选) - * @param endPriority 报警终止级别(可选) - * @param alarmMethod 报警方式条件(可选) - * @param alarmType 报警类型 - * @param startTime 报警发生起始时间(可选) - * @param endTime 报警发生终止时间(可选) - * @return true = 命令发送成功 - */ - @Override - public void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, - String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("Alarm\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - if (!ObjectUtils.isEmpty(startPriority)) { - cmdXml.append("" + startPriority + "\r\n"); - } - if (!ObjectUtils.isEmpty(endPriority)) { - cmdXml.append("" + endPriority + "\r\n"); - } - if (!ObjectUtils.isEmpty(alarmMethod)) { - cmdXml.append("" + alarmMethod + "\r\n"); - } - if (!ObjectUtils.isEmpty(alarmType)) { - cmdXml.append("" + alarmType + "\r\n"); - } - if (!ObjectUtils.isEmpty(startTime)) { - cmdXml.append("" + startTime + "\r\n"); - } - if (!ObjectUtils.isEmpty(endTime)) { - cmdXml.append("" + endTime + "\r\n"); - } - cmdXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); - } - - /** - * 查询设备配置 - * - * @param device 视频设备 - * @param channelId 通道编码(可选) - * @param configType 配置类型: - */ - @Override - public void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("ConfigDownload\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("" + configType + "\r\n"); - cmdXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); - } - - /** - * 查询设备预置位置 - * - * @param device 视频设备 - */ - @Override - public void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("PresetQuery\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); - } - cmdXml.append("\r\n"); - - - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); - } - - /** - * 查询移动设备位置数据 - * - * @param device 视频设备 - */ - @Override - public void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer mobilePostitionXml = new StringBuffer(200); - String charset = device.getCharset(); - mobilePostitionXml.append("\r\n"); - mobilePostitionXml.append("\r\n"); - mobilePostitionXml.append("MobilePosition\r\n"); - mobilePostitionXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - mobilePostitionXml.append("" + device.getDeviceId() + "\r\n"); - mobilePostitionXml.append("60\r\n"); - mobilePostitionXml.append("\r\n"); - - - - Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); - - } - - /** - * 订阅、取消订阅移动位置 - * - * @param device 视频设备 - * @return true = 命令发送成功 - */ - @Override - public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer subscribePostitionXml = new StringBuffer(200); - String charset = device.getCharset(); - subscribePostitionXml.append("\r\n"); - subscribePostitionXml.append("\r\n"); - subscribePostitionXml.append("MobilePosition\r\n"); - subscribePostitionXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - subscribePostitionXml.append("" + device.getDeviceId() + "\r\n"); - if (device.getSubscribeCycleForMobilePosition() > 0) { - subscribePostitionXml.append("" + device.getMobilePositionSubmissionInterval() + "\r\n"); - } - subscribePostitionXml.append("\r\n"); - - CallIdHeader callIdHeader; - - if (requestOld != null) { - callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); - } else { - callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); - } - SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence",callIdHeader); //Position;id=" + tm.substring(tm.length() - 4)); - - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); - return request; - } - - /** - * 订阅、取消订阅报警信息 - * - * @param device 视频设备 - * @param expires 订阅过期时间(0 = 取消订阅) - * @param startPriority 报警起始级别(可选) - * @param endPriority 报警终止级别(可选) - * @param alarmMethod 报警方式条件(可选) - * @param alarmType 报警类型 - * @param startTime 报警发生起始时间(可选) - * @param endTime 报警发生终止时间(可选) - * @return true = 命令发送成功 - */ - @Override - public void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("Alarm\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - if (!ObjectUtils.isEmpty(startPriority)) { - cmdXml.append("" + startPriority + "\r\n"); - } - if (!ObjectUtils.isEmpty(endPriority)) { - cmdXml.append("" + endPriority + "\r\n"); - } - if (!ObjectUtils.isEmpty(alarmMethod)) { - cmdXml.append("" + alarmMethod + "\r\n"); - } - if (!ObjectUtils.isEmpty(startTime)) { - cmdXml.append("" + startTime + "\r\n"); - } - if (!ObjectUtils.isEmpty(endTime)) { - cmdXml.append("" + endTime + "\r\n"); - } - cmdXml.append("\r\n"); - - - - Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence",sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); - - } - - @Override - public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer cmdXml = new StringBuffer(200); - String charset = device.getCharset(); - cmdXml.append("\r\n"); - cmdXml.append("\r\n"); - cmdXml.append("Catalog\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - cmdXml.append("" + device.getDeviceId() + "\r\n"); - cmdXml.append("\r\n"); - - CallIdHeader callIdHeader; - - if (requestOld != null) { - callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); - } else { - callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); - } - - // 有效时间默认为60秒以上 - SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog", - callIdHeader); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); - return request; - } - - @Override - public void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException { - - StringBuffer dragXml = new StringBuffer(200); - String charset = device.getCharset(); - dragXml.append("\r\n"); - dragXml.append("\r\n"); - dragXml.append("DeviceControl\r\n"); - dragXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - if (ObjectUtils.isEmpty(channelId)) { - dragXml.append("" + device.getDeviceId() + "\r\n"); - } else { - dragXml.append("" + channelId + "\r\n"); - } - dragXml.append(cmdString); - dragXml.append("\r\n"); - - Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - logger.debug("拉框信令: " + request.toString()); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); - } - - - - - - /** - * 回放暂停 - */ - @Override - public void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException { - StringBuffer content = new StringBuffer(200); - content.append("PAUSE RTSP/1.0\r\n"); - content.append("CSeq: " + getInfoCseq() + "\r\n"); - content.append("PauseTime: now\r\n"); - - playbackControlCmd(device, streamInfo, content.toString(), null, null); - } - - - /** - * 回放恢复 - */ - @Override - public void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException { - StringBuffer content = new StringBuffer(200); - content.append("PLAY RTSP/1.0\r\n"); - content.append("CSeq: " + getInfoCseq() + "\r\n"); - content.append("Range: npt=now-\r\n"); - - playbackControlCmd(device, streamInfo, content.toString(), null, null); - } - - /** - * 回放拖动播放 - */ - @Override - public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException { - StringBuffer content = new StringBuffer(200); - content.append("PLAY RTSP/1.0\r\n"); - content.append("CSeq: " + getInfoCseq() + "\r\n"); - content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n"); - - playbackControlCmd(device, streamInfo, content.toString(), null, null); - } - - /** - * 回放倍速播放 - */ - @Override - public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException { - StringBuffer content = new StringBuffer(200); - content.append("PLAY RTSP/1.0\r\n"); - content.append("CSeq: " + getInfoCseq() + "\r\n"); - content.append("Scale: " + String.format("%.6f", speed) + "\r\n"); - - playbackControlCmd(device, streamInfo, content.toString(), null, null); - } - - private int getInfoCseq() { - return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8)); - } - - @Override - public void playbackControlCmd(Device device, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException { - - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), streamInfo.getChannelId(), null, streamInfo.getStream()); - if (ssrcTransaction == null) { - logger.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); - return; - } - - SIPRequest request = headerProvider.createInfoRequest(device, streamInfo.getChannelId(), content.toString(), ssrcTransaction.getSipTransactionInfo()); - if (request == null) { - logger.info("[回放控制]构建Request信息失败,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); - return; - } - - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); - } - - @Override - public void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException { - if (device == null) { - return; - } - logger.info("[发送报警通知]设备: {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(), - deviceAlarm.getLongitude(), deviceAlarm.getLatitude()); - - String characterSet = device.getCharset(); - StringBuffer deviceStatusXml = new StringBuffer(600); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("Alarm\r\n"); - deviceStatusXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getChannelId() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmPriority() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmMethod() + "\r\n"); - deviceStatusXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(deviceAlarm.getAlarmTime()) + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmDescription() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getLongitude() + "\r\n"); - deviceStatusXml.append("" + deviceAlarm.getLatitude() + "\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("" + deviceAlarm.getAlarmType() + "\r\n"); - deviceStatusXml.append("\r\n"); - deviceStatusXml.append("\r\n"); - - - Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); - - - } -} +package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; + +import com.genersoft.iot.vmp.common.InviteSessionType; +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; +import com.genersoft.iot.vmp.gb28181.SipLayer; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; +import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; +import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; +import com.genersoft.iot.vmp.service.IMediaServerService; +import com.genersoft.iot.vmp.service.bean.SSRCInfo; +import com.genersoft.iot.vmp.utils.DateUtil; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import javax.sip.InvalidArgumentException; +import javax.sip.ResponseEvent; +import javax.sip.SipException; +import javax.sip.SipFactory; +import javax.sip.header.CallIdHeader; +import javax.sip.message.Request; +import java.text.ParseException; + +/** + * @description:设备能力接口,用于定义设备的控制、查询能力 + * @author: swwheihei + * @date: 2020年5月3日 下午9:22:48 + */ +@Component +@DependsOn("sipLayer") +public class SIPCommander implements ISIPCommander { + + private final Logger logger = LoggerFactory.getLogger(SIPCommander.class); + + @Autowired + private SipConfig sipConfig; + + @Autowired + private SipLayer sipLayer; + + @Autowired + private SIPSender sipSender; + + @Autowired + private SIPRequestHeaderProvider headerProvider; + + @Autowired + private VideoStreamSessionManager streamSession; + + @Autowired + private UserSetting userSetting; + + @Autowired + private ZlmHttpHookSubscribe subscribe; + + + + @Autowired + private IMediaServerService mediaServerService; + + + /** + * 云台方向放控制,使用配置文件中的默认镜头移动速度 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 + */ + @Override + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException { + ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0); + } + + /** + * 云台方向放控制 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 + * @param moveSpeed 镜头移动速度 + */ + @Override + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException { + ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0); + } + + /** + * 云台缩放控制,使用配置文件中的默认镜头缩放速度 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 + */ + @Override + public void ptzZoomCmd(Device device, String channelId, int inOut) throws InvalidArgumentException, ParseException, SipException { + ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed()); + } + + /** + * 云台缩放控制 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 + * @param zoomSpeed 镜头缩放速度 + */ + @Override + public void ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) throws InvalidArgumentException, ParseException, SipException { + ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed); + } + + /** + * 云台指令码计算 + * + * @param cmdCode 指令码 + * @param parameter1 数据1 + * @param parameter2 数据2 + * @param combineCode2 组合码2 + */ + public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) { + StringBuilder builder = new StringBuilder("A50F01"); + String strTmp; + strTmp = String.format("%02X", cmdCode); + builder.append(strTmp, 0, 2); + strTmp = String.format("%02X", parameter1); + builder.append(strTmp, 0, 2); + strTmp = String.format("%02X", parameter2); + builder.append(strTmp, 0, 2); + //优化zoom变倍速率 + if ((combineCode2 > 0) && (combineCode2 <16)) + { + combineCode2 = 16; + } + strTmp = String.format("%X", combineCode2); + builder.append(strTmp, 0, 1).append("0"); + //计算校验码 + int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100; + strTmp = String.format("%02X", checkCode); + builder.append(strTmp, 0, 2); + return builder.toString(); + } + + /** + * 云台控制,支持方向与缩放控制 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 + * @param moveSpeed 镜头移动速度 + * @param zoomSpeed 镜头缩放速度 + */ + @Override + public void ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed, + int zoomSpeed) throws InvalidArgumentException, SipException, ParseException { + String cmdStr = SipUtils.cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed); + StringBuilder ptzXml = new StringBuilder(200); + String charset = device.getCharset(); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("DeviceControl\r\n"); + ptzXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + ptzXml.append("" + channelId + "\r\n"); + ptzXml.append("" + cmdStr + "\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("5\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); + + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); + } + + /** + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param cmdCode 指令码 + * @param parameter1 数据1 + * @param parameter2 数据2 + * @param combineCode2 组合码2 + */ + @Override + public void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException { + + String cmdStr = frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2); + StringBuffer ptzXml = new StringBuffer(200); + String charset = device.getCharset(); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("DeviceControl\r\n"); + ptzXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + ptzXml.append("" + channelId + "\r\n"); + ptzXml.append("" + cmdStr + "\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("5\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); + + + + + SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); + + } + + /** + * 前端控制指令(用于转发上级指令) + * + * @param device 控制设备 + * @param channelId 预览通道 + * @param cmdString 前端控制指令串 + */ + @Override + public void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer ptzXml = new StringBuffer(200); + String charset = device.getCharset(); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("DeviceControl\r\n"); + ptzXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + ptzXml.append("" + channelId + "\r\n"); + ptzXml.append("" + cmdString + "\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("5\r\n"); + ptzXml.append("\r\n"); + ptzXml.append("\r\n"); + + + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request, errorEvent, okEvent); + + } + + /** + * 请求预览视频流 + * + * @param device 视频设备 + * @param channelId 预览通道 + * @param event hook订阅 + * @param errorEvent sip错误订阅 + */ + @Override + public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, + ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + String stream = ssrcInfo.getStream(); + + if (device == null) { + return; + } + + logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> { + if (event != null) { + event.response(mediaServerItemInUse, hookParam); + subscribe.removeSubscribe(hookSubscribe); + } + }); + String sdpIp; + if (!ObjectUtils.isEmpty(device.getSdpIp())) { + sdpIp = device.getSdpIp(); + }else { + sdpIp = mediaServerItem.getSdpIp(); + } + StringBuffer content = new StringBuffer(200); + content.append("v=0\r\n"); + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); + content.append("s=Play\r\n"); + content.append("c=IN IP4 " + sdpIp + "\r\n"); + content.append("t=0 0\r\n"); + + if (userSetting.isSeniorSdp()) { + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:126 H264/90000\r\n"); + content.append("a=rtpmap:125 H264S/90000\r\n"); + content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:99 H265/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } else { + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + content.append("a=rtpmap:99 H265/90000\r\n"); + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } + + if( device.isSwitchPrimarySubStream() ){ + if("TP-LINK".equals(device.getManufacturer())){ + if (device.isSwitchPrimarySubStream()){ + content.append("a=streamMode:sub\r\n"); + }else { + content.append("a=streamMode:main\r\n"); + } + }else { + if (device.isSwitchPrimarySubStream()){ + content.append("a=streamprofile:1\r\n"); + }else { + content.append("a=streamprofile:0\r\n"); + } + } + } + + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc + // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率 +// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备 + + + + Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> { + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); + errorEvent.response(e); + }), e -> { + ResponseEvent responseEvent = (ResponseEvent) e.event; + SIPResponse response = (SIPResponse) responseEvent.getResponse(); + streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, + InviteSessionType.PLAY); + okEvent.response(e); + }); + } + + /** + * 请求回放视频流 + * + * @param device 视频设备 + * @param channelId 预览通道 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss + */ + @Override + public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, + String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent, + SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); + String sdpIp; + if (!ObjectUtils.isEmpty(device.getSdpIp())) { + sdpIp = device.getSdpIp(); + }else { + sdpIp = mediaServerItem.getSdpIp(); + } + StringBuffer content = new StringBuffer(200); + content.append("v=0\r\n"); + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); + content.append("s=Playback\r\n"); + content.append("u=" + channelId + ":0\r\n"); + content.append("c=IN IP4 " + sdpIp + "\r\n"); + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " " + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n"); + + String streamMode = device.getStreamMode(); + + if (userSetting.isSeniorSdp()) { + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("UDP".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:126 H264/90000\r\n"); + content.append("a=rtpmap:125 H264S/90000\r\n"); + content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:99 H265/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } else { + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("UDP".equalsIgnoreCase(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:99 H265/90000\r\n"); + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { + // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { + // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } + + //ssrc + content.append("y=" + ssrcInfo.getSsrc() + "\r\n"); + + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); + // 添加订阅 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> { + if (hookEvent != null) { + hookEvent.response(mediaServerItemInUse, hookParam); + } + subscribe.removeSubscribe(hookSubscribe); + }); + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc()); + + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { + ResponseEvent responseEvent = (ResponseEvent) event.event; + SIPResponse response = (SIPResponse) responseEvent.getResponse(); + streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK); + okEvent.response(event); + }); + } + + /** + * 请求历史媒体下载 + * + * @param device 视频设备 + * @param channelId 预览通道 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param downloadSpeed 下载倍速参数 + */ + @Override + public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, + String startTime, String endTime, int downloadSpeed, + ZlmHttpHookSubscribe.Event hookEvent, + SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { + + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); + String sdpIp; + if (!ObjectUtils.isEmpty(device.getSdpIp())) { + sdpIp = device.getSdpIp(); + }else { + sdpIp = mediaServerItem.getSdpIp(); + } + StringBuffer content = new StringBuffer(200); + content.append("v=0\r\n"); + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); + content.append("s=Download\r\n"); + content.append("u=" + channelId + ":0\r\n"); + content.append("c=IN IP4 " + sdpIp + "\r\n"); + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " " + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n"); + + String streamMode = device.getStreamMode().toUpperCase(); + + if (userSetting.isSeniorSdp()) { + if ("TCP-PASSIVE".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("TCP-ACTIVE".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); + } else if ("UDP".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:126 H264/90000\r\n"); + content.append("a=rtpmap:125 H264S/90000\r\n"); + content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:99 MP4V-ES/90000\r\n"); + content.append("a=fmtp:99 profile-level-id=3\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } else { + if ("TCP-PASSIVE".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("TCP-ACTIVE".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); + } else if ("UDP".equals(streamMode)) { + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:99 H265/90000\r\n"); + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + } + content.append("a=downloadspeed:" + downloadSpeed + "\r\n"); + + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc + logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc()); + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); + // 添加订阅 + CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); + String callId= newCallIdHeader.getCallId(); + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> { + logger.debug("sipc 添加订阅===callId {}",callId); + hookEvent.response(mediaServerItemInUse, hookParam); + subscribe.removeSubscribe(hookSubscribe); + hookSubscribe.getContent().put("regist", false); + hookSubscribe.getContent().put("schema", "rtsp"); + // 添加流注销的订阅,注销了后向设备发送bye + subscribe.addSubscribe(hookSubscribe, + (mediaServerItemForEnd, hookParam1) -> { + logger.info("[录像]下载结束, 发送BYE"); + try { + streamByeCmd(device, channelId, ssrcInfo.getStream(), callId); + } catch (InvalidArgumentException | ParseException | SipException | + SsrcTransactionNotFoundException e) { + logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage()); + } + }); + }); + + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc()); + + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { + ResponseEvent responseEvent = (ResponseEvent) event.event; + SIPResponse response = (SIPResponse) responseEvent.getResponse(); + String contentString =new String(response.getRawContent()); + String ssrc = SipUtils.getSsrcFromSdp(contentString); + streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD); + okEvent.response(event); + }); + } + + /** + * 视频流停止, 不使用回调 + */ + @Override + public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException { + streamByeCmd(device, channelId, stream, callId, null); + } + + /** + * 视频流停止 + */ + @Override + public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callId, stream); + if (ssrcTransaction == null) { + throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream); + } + + mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); + mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); + streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); + + Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo()); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent); + } + + /** + * 语音广播 + * + * @param device 视频设备 + * @param channelId 预览通道 + */ + @Override + public void audioBroadcastCmd(Device device, String channelId) { + } + + /** + * 语音广播 + * + * @param device 视频设备 + */ + @Override + public void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer broadcastXml = new StringBuffer(200); + String charset = device.getCharset(); + broadcastXml.append("\r\n"); + broadcastXml.append("\r\n"); + broadcastXml.append("Broadcast\r\n"); + broadcastXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + broadcastXml.append("" + sipConfig.getId() + "\r\n"); + broadcastXml.append("" + device.getDeviceId() + "\r\n"); + broadcastXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); + + } + + @Override + public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer broadcastXml = new StringBuffer(200); + String charset = device.getCharset(); + broadcastXml.append("\r\n"); + broadcastXml.append("\r\n"); + broadcastXml.append("Broadcast\r\n"); + broadcastXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + broadcastXml.append("" + sipConfig.getId() + "\r\n"); + broadcastXml.append("" + device.getDeviceId() + "\r\n"); + broadcastXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + + } + + + /** + * 音视频录像控制 + * + * @param device 视频设备 + * @param channelId 预览通道 + * @param recordCmdStr 录像命令:Record / StopRecord + */ + @Override + public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("" + recordCmdStr + "\r\n"); + cmdXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); + } + + /** + * 远程启动控制命令 + * + * @param device 视频设备 + */ + @Override + public void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + cmdXml.append("Boot\r\n"); + cmdXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); + } + + /** + * 报警布防/撤防命令 + * + * @param device 视频设备 + * @param guardCmdStr "SetGuard"/"ResetGuard" + */ + @Override + public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + cmdXml.append("" + guardCmdStr + "\r\n"); + cmdXml.append("\r\n"); + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); + } + + /** + * 报警复位命令 + * + * @param device 视频设备 + */ + @Override + public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + cmdXml.append("ResetAlarm\r\n"); + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { + cmdXml.append("\r\n"); + } + if (!ObjectUtils.isEmpty(alarmMethod)) { + cmdXml.append("" + alarmMethod + "\r\n"); + } + if (!ObjectUtils.isEmpty(alarmType)) { + cmdXml.append("" + alarmType + "\r\n"); + } + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { + cmdXml.append("\r\n"); + } + cmdXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); + } + + /** + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 + * + * @param device 视频设备 + * @param channelId 预览通道 + */ + @Override + public void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("Send\r\n"); + cmdXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); + } + + /** + * 看守位控制命令 + * + * @param device 视频设备 + * @param channelId 通道id,非通道则是设备本身 + * @param enabled 看守位使能:1 = 开启,0 = 关闭 + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) + * @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 { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceControl\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("\r\n"); + if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) { + cmdXml.append("1\r\n"); + if (NumericUtil.isInteger(resetTime)) { + cmdXml.append("" + resetTime + "\r\n"); + } else { + cmdXml.append("0\r\n"); + } + if (NumericUtil.isInteger(presetIndex)) { + cmdXml.append("" + presetIndex + "\r\n"); + } else { + cmdXml.append("0\r\n"); + } + } else { + cmdXml.append("0\r\n"); + } + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); + } + + /** + * 设备配置命令 + * + * @param device 视频设备 + */ + @Override + public void deviceConfigCmd(Device device) { + // TODO Auto-generated method stub + } + + /** + * 设备配置命令:basicParam + * + * @param device 视频设备 + * @param channelId 通道编码(可选) + * @param name 设备/通道名称(可选) + * @param expiration 注册过期时间(可选) + * @param heartBeatInterval 心跳间隔时间(可选) + * @param heartBeatCount 心跳超时次数(可选) + */ + @Override + public void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, + String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("DeviceConfig\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("\r\n"); + if (!ObjectUtils.isEmpty(name)) { + cmdXml.append("" + name + "\r\n"); + } + if (NumericUtil.isInteger(expiration)) { + if (Integer.valueOf(expiration) > 0) { + cmdXml.append("" + expiration + "\r\n"); + } + } + if (NumericUtil.isInteger(heartBeatInterval)) { + if (Integer.valueOf(heartBeatInterval) > 0) { + cmdXml.append("" + heartBeatInterval + "\r\n"); + } + } + if (NumericUtil.isInteger(heartBeatCount)) { + if (Integer.valueOf(heartBeatCount) > 0) { + cmdXml.append("" + heartBeatCount + "\r\n"); + } + } + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + } + + /** + * 查询设备状态 + * + * @param device 视频设备 + */ + @Override + public void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + String charset = device.getCharset(); + StringBuffer catalogXml = new StringBuffer(200); + catalogXml.append("\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("DeviceStatus\r\n"); + catalogXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + catalogXml.append("" + device.getDeviceId() + "\r\n"); + catalogXml.append("\r\n"); + + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + } + + /** + * 查询设备信息 + * + * @param device 视频设备 + */ + @Override + public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer catalogXml = new StringBuffer(200); + String charset = device.getCharset(); + catalogXml.append("\r\n"); + catalogXml.append("\r\n"); + catalogXml.append("DeviceInfo\r\n"); + catalogXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + catalogXml.append("" + device.getDeviceId() + "\r\n"); + catalogXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); + + } + + /** + * 查询目录列表 + * + * @param device 视频设备 + */ + @Override + public void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException { + + StringBuffer catalogXml = new StringBuffer(200); + String charset = device.getCharset(); + catalogXml.append("\r\n"); + catalogXml.append("\r\n"); + catalogXml.append(" Catalog\r\n"); + catalogXml.append(" " + sn + "\r\n"); + catalogXml.append(" " + device.getDeviceId() + "\r\n"); + catalogXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + } + + /** + * 查询录像信息 + * + * @param device 视频设备 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss + */ + @Override + public void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + if (secrecy == null) { + secrecy = 0; + } + if (type == null) { + type = "all"; + } + + StringBuffer recordInfoXml = new StringBuffer(200); + String charset = device.getCharset(); + recordInfoXml.append("\r\n"); + recordInfoXml.append("\r\n"); + recordInfoXml.append("RecordInfo\r\n"); + recordInfoXml.append("" + sn + "\r\n"); + recordInfoXml.append("" + channelId + "\r\n"); + if (startTime != null) { + recordInfoXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "\r\n"); + } + if (endTime != null) { + recordInfoXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "\r\n"); + } + if (secrecy != null) { + recordInfoXml.append(" " + secrecy + " \r\n"); + } + if (type != null) { + // 大华NVR要求必须增加一个值为all的文本元素节点Type + recordInfoXml.append("" + type + "\r\n"); + } + recordInfoXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), + SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); + } + + /** + * 查询报警信息 + * + * @param device 视频设备 + * @param startPriority 报警起始级别(可选) + * @param endPriority 报警终止级别(可选) + * @param alarmMethod 报警方式条件(可选) + * @param alarmType 报警类型 + * @param startTime 报警发生起始时间(可选) + * @param endTime 报警发生终止时间(可选) + * @return true = 命令发送成功 + */ + @Override + public void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, + String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("Alarm\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + if (!ObjectUtils.isEmpty(startPriority)) { + cmdXml.append("" + startPriority + "\r\n"); + } + if (!ObjectUtils.isEmpty(endPriority)) { + cmdXml.append("" + endPriority + "\r\n"); + } + if (!ObjectUtils.isEmpty(alarmMethod)) { + cmdXml.append("" + alarmMethod + "\r\n"); + } + if (!ObjectUtils.isEmpty(alarmType)) { + cmdXml.append("" + alarmType + "\r\n"); + } + if (!ObjectUtils.isEmpty(startTime)) { + cmdXml.append("" + startTime + "\r\n"); + } + if (!ObjectUtils.isEmpty(endTime)) { + cmdXml.append("" + endTime + "\r\n"); + } + cmdXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + } + + /** + * 查询设备配置 + * + * @param device 视频设备 + * @param channelId 通道编码(可选) + * @param configType 配置类型: + */ + @Override + public void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("ConfigDownload\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("" + configType + "\r\n"); + cmdXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + } + + /** + * 查询设备预置位置 + * + * @param device 视频设备 + */ + @Override + public void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("PresetQuery\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + cmdXml.append("" + device.getDeviceId() + "\r\n"); + } else { + cmdXml.append("" + channelId + "\r\n"); + } + cmdXml.append("\r\n"); + + + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + } + + /** + * 查询移动设备位置数据 + * + * @param device 视频设备 + */ + @Override + public void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer mobilePostitionXml = new StringBuffer(200); + String charset = device.getCharset(); + mobilePostitionXml.append("\r\n"); + mobilePostitionXml.append("\r\n"); + mobilePostitionXml.append("MobilePosition\r\n"); + mobilePostitionXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + mobilePostitionXml.append("" + device.getDeviceId() + "\r\n"); + mobilePostitionXml.append("60\r\n"); + mobilePostitionXml.append("\r\n"); + + + + Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + + } + + /** + * 订阅、取消订阅移动位置 + * + * @param device 视频设备 + * @return true = 命令发送成功 + */ + @Override + public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer subscribePostitionXml = new StringBuffer(200); + String charset = device.getCharset(); + subscribePostitionXml.append("\r\n"); + subscribePostitionXml.append("\r\n"); + subscribePostitionXml.append("MobilePosition\r\n"); + subscribePostitionXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + subscribePostitionXml.append("" + device.getDeviceId() + "\r\n"); + if (device.getSubscribeCycleForMobilePosition() > 0) { + subscribePostitionXml.append("" + device.getMobilePositionSubmissionInterval() + "\r\n"); + } + subscribePostitionXml.append("\r\n"); + + CallIdHeader callIdHeader; + + if (requestOld != null) { + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); + } else { + callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); + } + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence",callIdHeader); //Position;id=" + tm.substring(tm.length() - 4)); + + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); + return request; + } + + /** + * 订阅、取消订阅报警信息 + * + * @param device 视频设备 + * @param expires 订阅过期时间(0 = 取消订阅) + * @param startPriority 报警起始级别(可选) + * @param endPriority 报警终止级别(可选) + * @param alarmMethod 报警方式条件(可选) + * @param alarmType 报警类型 + * @param startTime 报警发生起始时间(可选) + * @param endTime 报警发生终止时间(可选) + * @return true = 命令发送成功 + */ + @Override + public void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("Alarm\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + if (!ObjectUtils.isEmpty(startPriority)) { + cmdXml.append("" + startPriority + "\r\n"); + } + if (!ObjectUtils.isEmpty(endPriority)) { + cmdXml.append("" + endPriority + "\r\n"); + } + if (!ObjectUtils.isEmpty(alarmMethod)) { + cmdXml.append("" + alarmMethod + "\r\n"); + } + if (!ObjectUtils.isEmpty(startTime)) { + cmdXml.append("" + startTime + "\r\n"); + } + if (!ObjectUtils.isEmpty(endTime)) { + cmdXml.append("" + endTime + "\r\n"); + } + cmdXml.append("\r\n"); + + + + Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence",sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); + + } + + @Override + public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer cmdXml = new StringBuffer(200); + String charset = device.getCharset(); + cmdXml.append("\r\n"); + cmdXml.append("\r\n"); + cmdXml.append("Catalog\r\n"); + cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + device.getDeviceId() + "\r\n"); + cmdXml.append("\r\n"); + + CallIdHeader callIdHeader; + + if (requestOld != null) { + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); + } else { + callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); + } + + // 有效时间默认为60秒以上 + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog", + callIdHeader); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); + return request; + } + + @Override + public void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException { + + StringBuffer dragXml = new StringBuffer(200); + String charset = device.getCharset(); + dragXml.append("\r\n"); + dragXml.append("\r\n"); + dragXml.append("DeviceControl\r\n"); + dragXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + if (ObjectUtils.isEmpty(channelId)) { + dragXml.append("" + device.getDeviceId() + "\r\n"); + } else { + dragXml.append("" + channelId + "\r\n"); + } + dragXml.append(cmdString); + dragXml.append("\r\n"); + + Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + logger.debug("拉框信令: " + request.toString()); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); + } + + + + + + /** + * 回放暂停 + */ + @Override + public void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException { + StringBuffer content = new StringBuffer(200); + content.append("PAUSE RTSP/1.0\r\n"); + content.append("CSeq: " + getInfoCseq() + "\r\n"); + content.append("PauseTime: now\r\n"); + + playbackControlCmd(device, streamInfo, content.toString(), null, null); + } + + + /** + * 回放恢复 + */ + @Override + public void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException { + StringBuffer content = new StringBuffer(200); + content.append("PLAY RTSP/1.0\r\n"); + content.append("CSeq: " + getInfoCseq() + "\r\n"); + content.append("Range: npt=now-\r\n"); + + playbackControlCmd(device, streamInfo, content.toString(), null, null); + } + + /** + * 回放拖动播放 + */ + @Override + public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException { + StringBuffer content = new StringBuffer(200); + content.append("PLAY RTSP/1.0\r\n"); + content.append("CSeq: " + getInfoCseq() + "\r\n"); + content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n"); + + playbackControlCmd(device, streamInfo, content.toString(), null, null); + } + + /** + * 回放倍速播放 + */ + @Override + public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException { + StringBuffer content = new StringBuffer(200); + content.append("PLAY RTSP/1.0\r\n"); + content.append("CSeq: " + getInfoCseq() + "\r\n"); + content.append("Scale: " + String.format("%.6f", speed) + "\r\n"); + + playbackControlCmd(device, streamInfo, content.toString(), null, null); + } + + private int getInfoCseq() { + return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8)); + } + + @Override + public void playbackControlCmd(Device device, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException { + + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), streamInfo.getChannelId(), null, streamInfo.getStream()); + if (ssrcTransaction == null) { + logger.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); + return; + } + + SIPRequest request = headerProvider.createInfoRequest(device, streamInfo.getChannelId(), content.toString(), ssrcTransaction.getSipTransactionInfo()); + if (request == null) { + logger.info("[回放控制]构建Request信息失败,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); + return; + } + + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); + } + + @Override + public void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException { + if (device == null) { + return; + } + logger.info("[发送报警通知]设备: {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(), + deviceAlarm.getLongitude(), deviceAlarm.getLatitude()); + + String characterSet = device.getCharset(); + StringBuffer deviceStatusXml = new StringBuffer(600); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("Alarm\r\n"); + deviceStatusXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getChannelId() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmPriority() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmMethod() + "\r\n"); + deviceStatusXml.append("" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(deviceAlarm.getAlarmTime()) + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmDescription() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getLongitude() + "\r\n"); + deviceStatusXml.append("" + deviceAlarm.getLatitude() + "\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("" + deviceAlarm.getAlarmType() + "\r\n"); + deviceStatusXml.append("\r\n"); + deviceStatusXml.append("\r\n"); + + + Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); + + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/ISIPRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/ISIPRequestProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/CancelRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/CancelRequestProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java old mode 100644 new mode 100755 index fedf0eca..c794fdb2 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java @@ -1,149 +1,149 @@ -package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info; - -import com.genersoft.iot.vmp.common.InviteInfo; -import com.genersoft.iot.vmp.common.InviteSessionType; -import com.genersoft.iot.vmp.gb28181.bean.*; -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; -import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; -import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; -import com.genersoft.iot.vmp.gb28181.utils.SipUtils; -import com.genersoft.iot.vmp.service.IInviteStreamService; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.storager.IVideoManagerStorage; -import gov.nist.javax.sip.message.SIPRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.sip.InvalidArgumentException; -import javax.sip.RequestEvent; -import javax.sip.SipException; -import javax.sip.header.CallIdHeader; -import javax.sip.header.ContentTypeHeader; -import javax.sip.message.Response; -import java.text.ParseException; - -@Component -public class InfoRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { - - private final static Logger logger = LoggerFactory.getLogger(InfoRequestProcessor.class); - - private final String method = "INFO"; - - @Autowired - private SIPProcessorObserver sipProcessorObserver; - - @Autowired - private IVideoManagerStorage storage; - - @Autowired - private SipSubscribe sipSubscribe; - - @Autowired - private IRedisCatchStorage redisCatchStorage; - - @Autowired - private IInviteStreamService inviteStreamService; - - @Autowired - private IVideoManagerStorage storager; - - @Autowired - private SIPCommander cmder; - - @Autowired - private VideoStreamSessionManager sessionManager; - - @Override - public void afterPropertiesSet() throws Exception { - // 添加消息处理的订阅 - sipProcessorObserver.addRequestProcessor(method, this); - } - - @Override - public void process(RequestEvent evt) { - logger.debug("接收到消息:" + evt.getRequest()); - SIPRequest request = (SIPRequest) evt.getRequest(); - String deviceId = SipUtils.getUserIdFromFromHeader(request); - CallIdHeader callIdHeader = request.getCallIdHeader(); - // 先从会话内查找 - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); - - // 兼容海康 媒体通知 消息from字段不是设备ID的问题 - if (ssrcTransaction != null) { - deviceId = ssrcTransaction.getDeviceId(); - } - // 查询设备是否存在 - Device device = redisCatchStorage.getDevice(deviceId); - // 查询上级平台是否存在 - ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId); - try { - if (device != null && parentPlatform != null) { - logger.warn("[重复]平台与设备编号重复:{}", deviceId); - String hostAddress = request.getRemoteAddress().getHostAddress(); - int remotePort = request.getRemotePort(); - if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) { - parentPlatform = null; - }else { - device = null; - } - } - if (device == null && parentPlatform == null) { - // 不存在则回复404 - responseAck(request, Response.NOT_FOUND, "device "+ deviceId +" not found"); - logger.warn("[设备未找到 ]: {}", deviceId); - if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){ - DeviceNotFoundEvent deviceNotFoundEvent = new DeviceNotFoundEvent(evt.getDialog()); - deviceNotFoundEvent.setCallId(callIdHeader.getCallId()); - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent); - sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult); - }; - }else { - ContentTypeHeader header = (ContentTypeHeader)evt.getRequest().getHeader(ContentTypeHeader.NAME); - String contentType = header.getContentType(); - String contentSubType = header.getContentSubType(); - if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) { - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId()); - String streamId = sendRtpItem.getStreamId(); - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId); - if (null == inviteInfo) { - responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found"); - return; - } - Device device1 = storager.queryVideoDevice(inviteInfo.getDeviceId()); - if (inviteInfo.getStreamInfo() != null) { - cmder.playbackControlCmd(device1,inviteInfo.getStreamInfo(),new String(evt.getRequest().getRawContent()),eventResult -> { - // 失败的回复 - try { - responseAck(request, eventResult.statusCode, eventResult.msg); - } catch (SipException | InvalidArgumentException | ParseException e) { - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage()); - } - }, eventResult -> { - // 成功的回复 - try { - responseAck(request, eventResult.statusCode); - } catch (SipException | InvalidArgumentException | ParseException e) { - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage()); - } - }); - } - - } - } - } catch (SipException e) { - logger.warn("SIP 回复错误", e); - } catch (InvalidArgumentException e) { - logger.warn("参数无效", e); - } catch (ParseException e) { - logger.warn("SIP回复时解析异常", e); - } - } - - -} +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info; + +import com.genersoft.iot.vmp.common.InviteInfo; +import com.genersoft.iot.vmp.common.InviteSessionType; +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; +import com.genersoft.iot.vmp.service.IInviteStreamService; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import com.genersoft.iot.vmp.storager.IVideoManagerStorage; +import gov.nist.javax.sip.message.SIPRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.InvalidArgumentException; +import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.header.CallIdHeader; +import javax.sip.header.ContentTypeHeader; +import javax.sip.message.Response; +import java.text.ParseException; + +@Component +public class InfoRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { + + private final static Logger logger = LoggerFactory.getLogger(InfoRequestProcessor.class); + + private final String method = "INFO"; + + @Autowired + private SIPProcessorObserver sipProcessorObserver; + + @Autowired + private IVideoManagerStorage storage; + + @Autowired + private SipSubscribe sipSubscribe; + + @Autowired + private IRedisCatchStorage redisCatchStorage; + + @Autowired + private IInviteStreamService inviteStreamService; + + @Autowired + private IVideoManagerStorage storager; + + @Autowired + private SIPCommander cmder; + + @Autowired + private VideoStreamSessionManager sessionManager; + + @Override + public void afterPropertiesSet() throws Exception { + // 添加消息处理的订阅 + sipProcessorObserver.addRequestProcessor(method, this); + } + + @Override + public void process(RequestEvent evt) { + logger.debug("接收到消息:" + evt.getRequest()); + SIPRequest request = (SIPRequest) evt.getRequest(); + String deviceId = SipUtils.getUserIdFromFromHeader(request); + CallIdHeader callIdHeader = request.getCallIdHeader(); + // 先从会话内查找 + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); + + // 兼容海康 媒体通知 消息from字段不是设备ID的问题 + if (ssrcTransaction != null) { + deviceId = ssrcTransaction.getDeviceId(); + } + // 查询设备是否存在 + Device device = redisCatchStorage.getDevice(deviceId); + // 查询上级平台是否存在 + ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId); + try { + if (device != null && parentPlatform != null) { + logger.warn("[重复]平台与设备编号重复:{}", deviceId); + String hostAddress = request.getRemoteAddress().getHostAddress(); + int remotePort = request.getRemotePort(); + if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) { + parentPlatform = null; + }else { + device = null; + } + } + if (device == null && parentPlatform == null) { + // 不存在则回复404 + responseAck(request, Response.NOT_FOUND, "device "+ deviceId +" not found"); + logger.warn("[设备未找到 ]: {}", deviceId); + if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){ + DeviceNotFoundEvent deviceNotFoundEvent = new DeviceNotFoundEvent(evt.getDialog()); + deviceNotFoundEvent.setCallId(callIdHeader.getCallId()); + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent); + sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult); + }; + }else { + ContentTypeHeader header = (ContentTypeHeader)evt.getRequest().getHeader(ContentTypeHeader.NAME); + String contentType = header.getContentType(); + String contentSubType = header.getContentSubType(); + if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) { + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId()); + String streamId = sendRtpItem.getStreamId(); + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId); + if (null == inviteInfo) { + responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found"); + return; + } + Device device1 = storager.queryVideoDevice(inviteInfo.getDeviceId()); + if (inviteInfo.getStreamInfo() != null) { + cmder.playbackControlCmd(device1,inviteInfo.getStreamInfo(),new String(evt.getRequest().getRawContent()),eventResult -> { + // 失败的回复 + try { + responseAck(request, eventResult.statusCode, eventResult.msg); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage()); + } + }, eventResult -> { + // 成功的回复 + try { + responseAck(request, eventResult.statusCode); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage()); + } + }); + } + + } + } + } catch (SipException e) { + logger.warn("SIP 回复错误", e); + } catch (InvalidArgumentException e) { + logger.warn("参数无效", e); + } catch (ParseException e) { + logger.warn("SIP回复时解析异常", e); + } + } + + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/IMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/IMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/ControlMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/ControlMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/NotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/NotifyMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java old mode 100644 new mode 100755 index 7b9f69a3..7d94787e --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java @@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.utils.SipUtils; import com.genersoft.iot.vmp.service.IDeviceService; import com.genersoft.iot.vmp.utils.DateUtil; import gov.nist.javax.sip.message.SIPRequest; +import org.apache.commons.lang3.ObjectUtils; import org.dom4j.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -68,7 +69,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp } catch (SipException | InvalidArgumentException | ParseException e) { logger.error("[命令发送失败] 心跳回复: {}", e.getMessage()); } - if (DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L){ + if (!ObjectUtils.isEmpty(device.getKeepaliveTime()) && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L) { logger.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId()); return; } @@ -109,7 +110,11 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp @Override public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { - // 不会收到上级平台的心跳信息 - + // 个别平台保活不回复200OK会判定离线 + try { + responseAck((SIPRequest) evt.getRequest(), Response.OK); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 心跳回复: {}", e.getMessage()); + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/QueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/QueryMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/AlarmQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/AlarmQueryMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/ISIPResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/ISIPResponseProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/SIPResponseProcessorAbstract.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/SIPResponseProcessorAbstract.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/ByeResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/ByeResponseProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/CancelResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/CancelResponseProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/ITimeoutProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/ITimeoutProcessor.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java index 8c96a8e8..e614b9fd 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java @@ -1,647 +1,647 @@ -package com.genersoft.iot.vmp.gb28181.utils; - -import com.alibaba.fastjson2.JSONArray; -import com.alibaba.fastjson2.JSONObject; -import com.genersoft.iot.vmp.common.CivilCodePo; -import com.genersoft.iot.vmp.conf.CivilCodeFileConf; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; -import com.genersoft.iot.vmp.utils.DateUtil; -import org.apache.commons.lang3.math.NumberUtils; -import org.dom4j.Attribute; -import org.dom4j.Document; -import org.dom4j.DocumentException; -import org.dom4j.Element; -import org.dom4j.io.SAXReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.ObjectUtils; -import org.springframework.util.ReflectionUtils; - -import javax.sip.RequestEvent; -import javax.sip.message.Request; -import java.io.ByteArrayInputStream; -import java.io.StringReader; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.*; - -/** - * 基于dom4j的工具包 - * - * - */ -public class XmlUtil { - /** - * 日志服务 - */ - private static Logger logger = LoggerFactory.getLogger(XmlUtil.class); - - /** - * 解析XML为Document对象 - * - * @param xml 被解析的XMl - * - * @return Document - */ - public static Element parseXml(String xml) { - Document document = null; - // - StringReader sr = new StringReader(xml); - SAXReader saxReader = new SAXReader(); - try { - document = saxReader.read(sr); - } catch (DocumentException e) { - logger.error("解析失败", e); - } - return null == document ? null : document.getRootElement(); - } - - /** - * 获取element对象的text的值 - * - * @param em 节点的对象 - * @param tag 节点的tag - * @return 节点 - */ - public static String getText(Element em, String tag) { - if (null == em) { - return null; - } - Element e = em.element(tag); - // - return null == e ? null : e.getText().trim(); - } - - /** - * 递归解析xml节点,适用于 多节点数据 - * - * @param node node - * @param nodeName nodeName - * @return List> - */ - public static List> listNodes(Element node, String nodeName) { - if (null == node) { - return null; - } - // 初始化返回 - List> listMap = new ArrayList>(); - // 首先获取当前节点的所有属性节点 - List list = node.attributes(); - - Map map = null; - // 遍历属性节点 - for (Attribute attribute : list) { - if (nodeName.equals(node.getName())) { - if (null == map) { - map = new HashMap(); - listMap.add(map); - } - // 取到的节点属性放到map中 - map.put(attribute.getName(), attribute.getValue()); - } - - } - // 遍历当前节点下的所有节点 ,nodeName 要解析的节点名称 - // 使用递归 - Iterator iterator = node.elementIterator(); - while (iterator.hasNext()) { - Element e = iterator.next(); - listMap.addAll(listNodes(e, nodeName)); - } - return listMap; - } - - /** - * xml转json - * - * @param element - * @param json - */ - public static void node2Json(Element element, JSONObject json) { - // 如果是属性 - for (Object o : element.attributes()) { - Attribute attr = (Attribute) o; - if (!ObjectUtils.isEmpty(attr.getValue())) { - json.put("@" + attr.getName(), attr.getValue()); - } - } - List chdEl = element.elements(); - if (chdEl.isEmpty() && !ObjectUtils.isEmpty(element.getText())) {// 如果没有子元素,只有一个值 - json.put(element.getName(), element.getText()); - } - - for (Element e : chdEl) { // 有子元素 - if (!e.elements().isEmpty()) { // 子元素也有子元素 - JSONObject chdjson = new JSONObject(); - node2Json(e, chdjson); - Object o = json.get(e.getName()); - if (o != null) { - JSONArray jsona = null; - if (o instanceof JSONObject) { // 如果此元素已存在,则转为jsonArray - JSONObject jsono = (JSONObject) o; - json.remove(e.getName()); - jsona = new JSONArray(); - jsona.add(jsono); - jsona.add(chdjson); - } - if (o instanceof JSONArray) { - jsona = (JSONArray) o; - jsona.add(chdjson); - } - json.put(e.getName(), jsona); - } else { - if (!chdjson.isEmpty()) { - json.put(e.getName(), chdjson); - } - } - } else { // 子元素没有子元素 - for (Object o : element.attributes()) { - Attribute attr = (Attribute) o; - if (!ObjectUtils.isEmpty(attr.getValue())) { - json.put("@" + attr.getName(), attr.getValue()); - } - } - if (!e.getText().isEmpty()) { - json.put(e.getName(), e.getText()); - } - } - } - } - public static Element getRootElement(RequestEvent evt) throws DocumentException { - - return getRootElement(evt, "gb2312"); - } - - public static Element getRootElement(RequestEvent evt, String charset) throws DocumentException { - Request request = evt.getRequest(); - return getRootElement(request.getRawContent(), charset); - } - - public static Element getRootElement(byte[] content, String charset) throws DocumentException { - if (charset == null) { - charset = "gb2312"; - } - SAXReader reader = new SAXReader(); - reader.setEncoding(charset); - Document xml = reader.read(new ByteArrayInputStream(content)); - return xml.getRootElement(); - } - - private enum ChannelType{ - CivilCode, BusinessGroup,VirtualOrganization,Other - } - - public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event, CivilCodeFileConf civilCodeFileConf){ - DeviceChannel deviceChannel = new DeviceChannel(); - deviceChannel.setDeviceId(device.getDeviceId()); - Element channdelIdElement = itemDevice.element("DeviceID"); - if (channdelIdElement == null) { - logger.warn("解析Catalog消息时发现缺少 DeviceID"); - return null; - } - String channelId = channdelIdElement.getTextTrim(); - if (ObjectUtils.isEmpty(channelId)) { - logger.warn("解析Catalog消息时发现缺少 DeviceID"); - return null; - } - deviceChannel.setChannelId(channelId); - if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) { - // 除了ADD和update情况下需要识别全部内容, - return deviceChannel; - } - Element nameElement = itemDevice.element("Name"); - if (nameElement != null) { - deviceChannel.setName(nameElement.getText()); - } - if(channelId.length() <= 8) { - deviceChannel.setHasAudio(false); - CivilCodePo parentCode = civilCodeFileConf.getParentCode(channelId); - if (parentCode != null) { - deviceChannel.setParentId(parentCode.getCode()); - deviceChannel.setCivilCode(parentCode.getCode()); - }else { - logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId); - } - deviceChannel.setStatus(true); - return deviceChannel; - }else { - if(channelId.length() != 20) { - logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId); - return null; - } - - int code = Integer.parseInt(channelId.substring(10, 13)); - if (code == 136 || code == 137 || code == 138) { - deviceChannel.setHasAudio(true); - }else { - deviceChannel.setHasAudio(false); - } - // 设备厂商 - String manufacturer = getText(itemDevice, "Manufacturer"); - // 设备型号 - String model = getText(itemDevice, "Model"); - // 设备归属 - String owner = getText(itemDevice, "Owner"); - // 行政区域 - String civilCode = getText(itemDevice, "CivilCode"); - // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织 - String businessGroupID = getText(itemDevice, "BusinessGroupID"); - // 父设备/区域/系统ID - String parentID = getText(itemDevice, "ParentID"); - if (parentID != null && parentID.equalsIgnoreCase("null")) { - parentID = null; - } - // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式 - String registerWay = getText(itemDevice, "RegisterWay"); - // 保密属性(必选)缺省为0;0:不涉密,1:涉密 - String secrecy = getText(itemDevice, "Secrecy"); - // 安装地址 - String address = getText(itemDevice, "Address"); - - switch (code){ - case 200: - // 系统目录 - if (!ObjectUtils.isEmpty(manufacturer)) { - deviceChannel.setManufacture(manufacturer); - } - if (!ObjectUtils.isEmpty(model)) { - deviceChannel.setModel(model); - } - if (!ObjectUtils.isEmpty(owner)) { - deviceChannel.setOwner(owner); - } - if (!ObjectUtils.isEmpty(civilCode)) { - deviceChannel.setCivilCode(civilCode); - deviceChannel.setParentId(civilCode); - }else { - if (!ObjectUtils.isEmpty(parentID)) { - deviceChannel.setParentId(parentID); - } - } - if (!ObjectUtils.isEmpty(address)) { - deviceChannel.setAddress(address); - } - deviceChannel.setStatus(true); - if (!ObjectUtils.isEmpty(registerWay)) { - try { - deviceChannel.setRegisterWay(Integer.parseInt(registerWay)); - }catch (NumberFormatException exception) { - logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); - } - } - if (!ObjectUtils.isEmpty(secrecy)) { - deviceChannel.setSecrecy(secrecy); - } - return deviceChannel; - case 215: - // 业务分组 - deviceChannel.setStatus(true); - if (!ObjectUtils.isEmpty(parentID)) { - if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) { - deviceChannel.setParentId(parentID); - } - }else { - logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId"); - if (!ObjectUtils.isEmpty(civilCode)) { - deviceChannel.setCivilCode(civilCode); - } - } - break; - case 216: - // 虚拟组织 - deviceChannel.setStatus(true); - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setBusinessGroupId(businessGroupID); - } - - if (!ObjectUtils.isEmpty(parentID)) { - if (parentID.contains("/")) { - String[] parentIdArray = parentID.split("/"); - parentID = parentIdArray[parentIdArray.length - 1]; - } - deviceChannel.setParentId(parentID); - }else { - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setParentId(businessGroupID); - } - } - break; - default: - // 设备目录 - if (!ObjectUtils.isEmpty(manufacturer)) { - deviceChannel.setManufacture(manufacturer); - } - if (!ObjectUtils.isEmpty(model)) { - deviceChannel.setModel(model); - } - if (!ObjectUtils.isEmpty(owner)) { - deviceChannel.setOwner(owner); - } - if (!ObjectUtils.isEmpty(civilCode) - && civilCode.length() <= 8 - && NumberUtils.isParsable(civilCode) - && civilCode.length()%2 == 0 - ) { - deviceChannel.setCivilCode(civilCode); - } - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setBusinessGroupId(businessGroupID); - } - - // 警区 - String block = getText(itemDevice, "Block"); - if (!ObjectUtils.isEmpty(block)) { - deviceChannel.setBlock(block); - } - if (!ObjectUtils.isEmpty(address)) { - deviceChannel.setAddress(address); - } - - if (!ObjectUtils.isEmpty(secrecy)) { - deviceChannel.setSecrecy(secrecy); - } - - // 当为设备时,是否有子设备(必选)1有,0没有 - String parental = getText(itemDevice, "Parental"); - if (!ObjectUtils.isEmpty(parental)) { - try { - // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 - if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) { - deviceChannel.setParental(0); - }else { - deviceChannel.setParental(1); - } - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental); - } - } - // 父设备/区域/系统ID - - if (!ObjectUtils.isEmpty(parentID) ) { - if (parentID.contains("/")) { - String[] parentIdArray = parentID.split("/"); - deviceChannel.setParentId(parentIdArray[parentIdArray.length - 1]); - }else { - if (parentID.length()%2 == 0) { - deviceChannel.setParentId(parentID); - }else { - logger.warn("[xml解析] 不规范的parentID:{}, 已舍弃", parentID); - } - } - }else { - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setParentId(businessGroupID); - }else { - if (!ObjectUtils.isEmpty(deviceChannel.getCivilCode())) { - deviceChannel.setParentId(deviceChannel.getCivilCode()); - } - } - } - // 注册方式 - if (!ObjectUtils.isEmpty(registerWay)) { - try { - int registerWayInt = Integer.parseInt(registerWay); - deviceChannel.setRegisterWay(registerWayInt); - }catch (NumberFormatException exception) { - logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); - deviceChannel.setRegisterWay(1); - } - }else { - deviceChannel.setRegisterWay(1); - } - - // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式 - String safetyWay = getText(itemDevice, "SafetyWay"); - if (!ObjectUtils.isEmpty(safetyWay)) { - try { - deviceChannel.setSafetyWay(Integer.parseInt(safetyWay)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay); - } - } - - // 证书序列号(有证书的设备必选) - String certNum = getText(itemDevice, "CertNum"); - if (!ObjectUtils.isEmpty(certNum)) { - deviceChannel.setCertNum(certNum); - } - - // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效 - String certifiable = getText(itemDevice, "Certifiable"); - if (!ObjectUtils.isEmpty(certifiable)) { - try { - deviceChannel.setCertifiable(Integer.parseInt(certifiable)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable); - } - } - - // 无效原因码(有证书且证书无效的设备必选) - String errCode = getText(itemDevice, "ErrCode"); - if (!ObjectUtils.isEmpty(errCode)) { - try { - deviceChannel.setErrCode(Integer.parseInt(errCode)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode); - } - } - - // 证书终止有效期(有证书的设备必选) - String endTime = getText(itemDevice, "EndTime"); - if (!ObjectUtils.isEmpty(endTime)) { - deviceChannel.setEndTime(endTime); - } - - - // 设备/区域/系统IP地址 - String ipAddress = getText(itemDevice, "IPAddress"); - if (!ObjectUtils.isEmpty(ipAddress)) { - deviceChannel.setIpAddress(ipAddress); - } - - // 设备/区域/系统端口 - String port = getText(itemDevice, "Port"); - if (!ObjectUtils.isEmpty(port)) { - try { - deviceChannel.setPort(Integer.parseInt(port)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port); - } - } - - // 设备口令 - String password = getText(itemDevice, "Password"); - if (!ObjectUtils.isEmpty(password)) { - deviceChannel.setPassword(password); - } - - - // 设备状态 - String status = getText(itemDevice, "Status"); - if (status != null) { - // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 - if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) { - deviceChannel.setStatus(true); - } - if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { - deviceChannel.setStatus(false); - } - }else { - deviceChannel.setStatus(true); - } - - // 经度 - String longitude = getText(itemDevice, "Longitude"); - if (NumericUtil.isDouble(longitude)) { - deviceChannel.setLongitude(Double.parseDouble(longitude)); - } else { - deviceChannel.setLongitude(0.00); - } - - // 纬度 - String latitude = getText(itemDevice, "Latitude"); - if (NumericUtil.isDouble(latitude)) { - deviceChannel.setLatitude(Double.parseDouble(latitude)); - } else { - deviceChannel.setLatitude(0.00); - } - - deviceChannel.setGpsTime(DateUtil.getNow()); - - // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选 - String ptzType = getText(itemDevice, "PTZType"); - if (ObjectUtils.isEmpty(ptzType)) { - //兼容INFO中的信息 - Element info = itemDevice.element("Info"); - String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType"); - if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){ - try { - deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo)); - }catch (NumberFormatException e){ - logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo); - } - } - } else { - try { - deviceChannel.setPTZType(Integer.parseInt(ptzType)); - }catch (NumberFormatException e){ - logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType); - } - } - - // TODO 摄像机位置类型扩展。 - // 1-省际检查站、 - // 2-党政机关、 - // 3-车站码头、 - // 4-中心广场、 - // 5-体育场馆、 - // 6-商业中心、 - // 7-宗教场所、 - // 8-校园周边、 - // 9-治安复杂区域、 - // 10-交通干线。 - // String positionType = getText(itemDevice, "PositionType"); - - // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。 - // String roomType = getText(itemDevice, "RoomType"); - // TODO 摄像机用途属性 - // String useType = getText(itemDevice, "UseType"); - // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光 - // String supplyLightType = getText(itemDevice, "SupplyLightType"); - // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。 - // String directionType = getText(itemDevice, "DirectionType"); - // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定 - // String resolution = getText(itemDevice, "Resolution"); - - // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4 - // String downloadSpeed = getText(itemDevice, "DownloadSpeed"); - // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层) - // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode"); - // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强 - // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode"); - - - deviceChannel.setSecrecy(secrecy); - break; - } - } - - return deviceChannel; - } - - /** - * 新增方法支持内部嵌套 - * - * @param element xmlElement - * @param clazz 结果类 - * @param 泛型 - * @return 结果对象 - * @throws NoSuchMethodException - * @throws InvocationTargetException - * @throws InstantiationException - * @throws IllegalAccessException - */ - public static T loadElement(Element element, Class clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { - Field[] fields = clazz.getDeclaredFields(); - T t = clazz.getDeclaredConstructor().newInstance(); - for (Field field : fields) { - ReflectionUtils.makeAccessible(field); - MessageElement annotation = field.getAnnotation(MessageElement.class); - if (annotation == null) { - continue; - } - String value = annotation.value(); - String subVal = annotation.subVal(); - Element element1 = element.element(value); - if (element1 == null) { - continue; - } - if ("".equals(subVal)) { - // 无下级数据 - Object fieldVal = element1.isTextOnly() ? element1.getText() : loadElement(element1, field.getType()); - Object o = simpleTypeDeal(field.getType(), fieldVal); - ReflectionUtils.setField(field, t, o); - } else { - // 存在下级数据 - ArrayList list = new ArrayList<>(); - Type genericType = field.getGenericType(); - if (!(genericType instanceof ParameterizedType)) { - continue; - } - Class aClass = (Class) ((ParameterizedType) genericType).getActualTypeArguments()[0]; - for (Element element2 : element1.elements(subVal)) { - list.add(loadElement(element2, aClass)); - } - ReflectionUtils.setField(field, t, list); - } - } - return t; - } - - /** - * 简单类型处理 - * - * @param tClass - * @param val - * @return - */ - private static Object simpleTypeDeal(Class tClass, Object val) { - if (tClass.equals(String.class)) { - return val.toString(); - } - if (tClass.equals(Integer.class)) { - return Integer.valueOf(val.toString()); - } - if (tClass.equals(Double.class)) { - return Double.valueOf(val.toString()); - } - if (tClass.equals(Long.class)) { - return Long.valueOf(val.toString()); - } - return val; - } +package com.genersoft.iot.vmp.gb28181.utils; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.common.CivilCodePo; +import com.genersoft.iot.vmp.conf.CivilCodeFileConf; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; +import com.genersoft.iot.vmp.utils.DateUtil; +import org.apache.commons.lang3.math.NumberUtils; +import org.dom4j.Attribute; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.ObjectUtils; +import org.springframework.util.ReflectionUtils; + +import javax.sip.RequestEvent; +import javax.sip.message.Request; +import java.io.ByteArrayInputStream; +import java.io.StringReader; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.*; + +/** + * 基于dom4j的工具包 + * + * + */ +public class XmlUtil { + /** + * 日志服务 + */ + private static Logger logger = LoggerFactory.getLogger(XmlUtil.class); + + /** + * 解析XML为Document对象 + * + * @param xml 被解析的XMl + * + * @return Document + */ + public static Element parseXml(String xml) { + Document document = null; + // + StringReader sr = new StringReader(xml); + SAXReader saxReader = new SAXReader(); + try { + document = saxReader.read(sr); + } catch (DocumentException e) { + logger.error("解析失败", e); + } + return null == document ? null : document.getRootElement(); + } + + /** + * 获取element对象的text的值 + * + * @param em 节点的对象 + * @param tag 节点的tag + * @return 节点 + */ + public static String getText(Element em, String tag) { + if (null == em) { + return null; + } + Element e = em.element(tag); + // + return null == e ? null : e.getText().trim(); + } + + /** + * 递归解析xml节点,适用于 多节点数据 + * + * @param node node + * @param nodeName nodeName + * @return List> + */ + public static List> listNodes(Element node, String nodeName) { + if (null == node) { + return null; + } + // 初始化返回 + List> listMap = new ArrayList>(); + // 首先获取当前节点的所有属性节点 + List list = node.attributes(); + + Map map = null; + // 遍历属性节点 + for (Attribute attribute : list) { + if (nodeName.equals(node.getName())) { + if (null == map) { + map = new HashMap(); + listMap.add(map); + } + // 取到的节点属性放到map中 + map.put(attribute.getName(), attribute.getValue()); + } + + } + // 遍历当前节点下的所有节点 ,nodeName 要解析的节点名称 + // 使用递归 + Iterator iterator = node.elementIterator(); + while (iterator.hasNext()) { + Element e = iterator.next(); + listMap.addAll(listNodes(e, nodeName)); + } + return listMap; + } + + /** + * xml转json + * + * @param element + * @param json + */ + public static void node2Json(Element element, JSONObject json) { + // 如果是属性 + for (Object o : element.attributes()) { + Attribute attr = (Attribute) o; + if (!ObjectUtils.isEmpty(attr.getValue())) { + json.put("@" + attr.getName(), attr.getValue()); + } + } + List chdEl = element.elements(); + if (chdEl.isEmpty() && !ObjectUtils.isEmpty(element.getText())) {// 如果没有子元素,只有一个值 + json.put(element.getName(), element.getText()); + } + + for (Element e : chdEl) { // 有子元素 + if (!e.elements().isEmpty()) { // 子元素也有子元素 + JSONObject chdjson = new JSONObject(); + node2Json(e, chdjson); + Object o = json.get(e.getName()); + if (o != null) { + JSONArray jsona = null; + if (o instanceof JSONObject) { // 如果此元素已存在,则转为jsonArray + JSONObject jsono = (JSONObject) o; + json.remove(e.getName()); + jsona = new JSONArray(); + jsona.add(jsono); + jsona.add(chdjson); + } + if (o instanceof JSONArray) { + jsona = (JSONArray) o; + jsona.add(chdjson); + } + json.put(e.getName(), jsona); + } else { + if (!chdjson.isEmpty()) { + json.put(e.getName(), chdjson); + } + } + } else { // 子元素没有子元素 + for (Object o : element.attributes()) { + Attribute attr = (Attribute) o; + if (!ObjectUtils.isEmpty(attr.getValue())) { + json.put("@" + attr.getName(), attr.getValue()); + } + } + if (!e.getText().isEmpty()) { + json.put(e.getName(), e.getText()); + } + } + } + } + public static Element getRootElement(RequestEvent evt) throws DocumentException { + + return getRootElement(evt, "gb2312"); + } + + public static Element getRootElement(RequestEvent evt, String charset) throws DocumentException { + Request request = evt.getRequest(); + return getRootElement(request.getRawContent(), charset); + } + + public static Element getRootElement(byte[] content, String charset) throws DocumentException { + if (charset == null) { + charset = "gb2312"; + } + SAXReader reader = new SAXReader(); + reader.setEncoding(charset); + Document xml = reader.read(new ByteArrayInputStream(content)); + return xml.getRootElement(); + } + + private enum ChannelType{ + CivilCode, BusinessGroup,VirtualOrganization,Other + } + + public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event, CivilCodeFileConf civilCodeFileConf){ + DeviceChannel deviceChannel = new DeviceChannel(); + deviceChannel.setDeviceId(device.getDeviceId()); + Element channdelIdElement = itemDevice.element("DeviceID"); + if (channdelIdElement == null) { + logger.warn("解析Catalog消息时发现缺少 DeviceID"); + return null; + } + String channelId = channdelIdElement.getTextTrim(); + if (ObjectUtils.isEmpty(channelId)) { + logger.warn("解析Catalog消息时发现缺少 DeviceID"); + return null; + } + deviceChannel.setChannelId(channelId); + if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) { + // 除了ADD和update情况下需要识别全部内容, + return deviceChannel; + } + Element nameElement = itemDevice.element("Name"); + if (nameElement != null) { + deviceChannel.setName(nameElement.getText()); + } + if(channelId.length() <= 8) { + deviceChannel.setHasAudio(false); + CivilCodePo parentCode = civilCodeFileConf.getParentCode(channelId); + if (parentCode != null) { + deviceChannel.setParentId(parentCode.getCode()); + deviceChannel.setCivilCode(parentCode.getCode()); + }else { + logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId); + } + deviceChannel.setStatus(true); + return deviceChannel; + }else { + if(channelId.length() != 20) { + logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId); + return null; + } + + int code = Integer.parseInt(channelId.substring(10, 13)); + if (code == 136 || code == 137 || code == 138) { + deviceChannel.setHasAudio(true); + }else { + deviceChannel.setHasAudio(false); + } + // 设备厂商 + String manufacturer = getText(itemDevice, "Manufacturer"); + // 设备型号 + String model = getText(itemDevice, "Model"); + // 设备归属 + String owner = getText(itemDevice, "Owner"); + // 行政区域 + String civilCode = getText(itemDevice, "CivilCode"); + // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织 + String businessGroupID = getText(itemDevice, "BusinessGroupID"); + // 父设备/区域/系统ID + String parentID = getText(itemDevice, "ParentID"); + if (parentID != null && parentID.equalsIgnoreCase("null")) { + parentID = null; + } + // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式 + String registerWay = getText(itemDevice, "RegisterWay"); + // 保密属性(必选)缺省为0;0:不涉密,1:涉密 + String secrecy = getText(itemDevice, "Secrecy"); + // 安装地址 + String address = getText(itemDevice, "Address"); + + switch (code){ + case 200: + // 系统目录 + if (!ObjectUtils.isEmpty(manufacturer)) { + deviceChannel.setManufacture(manufacturer); + } + if (!ObjectUtils.isEmpty(model)) { + deviceChannel.setModel(model); + } + if (!ObjectUtils.isEmpty(owner)) { + deviceChannel.setOwner(owner); + } + if (!ObjectUtils.isEmpty(civilCode)) { + deviceChannel.setCivilCode(civilCode); + deviceChannel.setParentId(civilCode); + }else { + if (!ObjectUtils.isEmpty(parentID)) { + deviceChannel.setParentId(parentID); + } + } + if (!ObjectUtils.isEmpty(address)) { + deviceChannel.setAddress(address); + } + deviceChannel.setStatus(true); + if (!ObjectUtils.isEmpty(registerWay)) { + try { + deviceChannel.setRegisterWay(Integer.parseInt(registerWay)); + }catch (NumberFormatException exception) { + logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); + } + } + if (!ObjectUtils.isEmpty(secrecy)) { + deviceChannel.setSecrecy(secrecy); + } + return deviceChannel; + case 215: + // 业务分组 + deviceChannel.setStatus(true); + if (!ObjectUtils.isEmpty(parentID)) { + if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) { + deviceChannel.setParentId(parentID); + } + }else { + logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId"); + if (!ObjectUtils.isEmpty(civilCode)) { + deviceChannel.setCivilCode(civilCode); + } + } + break; + case 216: + // 虚拟组织 + deviceChannel.setStatus(true); + if (!ObjectUtils.isEmpty(businessGroupID)) { + deviceChannel.setBusinessGroupId(businessGroupID); + } + + if (!ObjectUtils.isEmpty(parentID)) { + if (parentID.contains("/")) { + String[] parentIdArray = parentID.split("/"); + parentID = parentIdArray[parentIdArray.length - 1]; + } + deviceChannel.setParentId(parentID); + }else { + if (!ObjectUtils.isEmpty(businessGroupID)) { + deviceChannel.setParentId(businessGroupID); + } + } + break; + default: + // 设备目录 + if (!ObjectUtils.isEmpty(manufacturer)) { + deviceChannel.setManufacture(manufacturer); + } + if (!ObjectUtils.isEmpty(model)) { + deviceChannel.setModel(model); + } + if (!ObjectUtils.isEmpty(owner)) { + deviceChannel.setOwner(owner); + } + if (!ObjectUtils.isEmpty(civilCode) + && civilCode.length() <= 8 + && NumberUtils.isParsable(civilCode) + && civilCode.length()%2 == 0 + ) { + deviceChannel.setCivilCode(civilCode); + } + if (!ObjectUtils.isEmpty(businessGroupID)) { + deviceChannel.setBusinessGroupId(businessGroupID); + } + + // 警区 + String block = getText(itemDevice, "Block"); + if (!ObjectUtils.isEmpty(block)) { + deviceChannel.setBlock(block); + } + if (!ObjectUtils.isEmpty(address)) { + deviceChannel.setAddress(address); + } + + if (!ObjectUtils.isEmpty(secrecy)) { + deviceChannel.setSecrecy(secrecy); + } + + // 当为设备时,是否有子设备(必选)1有,0没有 + String parental = getText(itemDevice, "Parental"); + if (!ObjectUtils.isEmpty(parental)) { + try { + // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 + if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) { + deviceChannel.setParental(0); + }else { + deviceChannel.setParental(1); + } + }catch (NumberFormatException e) { + logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental); + } + } + // 父设备/区域/系统ID + + if (!ObjectUtils.isEmpty(parentID) ) { + if (parentID.contains("/")) { + String[] parentIdArray = parentID.split("/"); + deviceChannel.setParentId(parentIdArray[parentIdArray.length - 1]); + }else { + if (parentID.length()%2 == 0) { + deviceChannel.setParentId(parentID); + }else { + logger.warn("[xml解析] 不规范的parentID:{}, 已舍弃", parentID); + } + } + }else { + if (!ObjectUtils.isEmpty(businessGroupID)) { + deviceChannel.setParentId(businessGroupID); + }else { + if (!ObjectUtils.isEmpty(deviceChannel.getCivilCode())) { + deviceChannel.setParentId(deviceChannel.getCivilCode()); + } + } + } + // 注册方式 + if (!ObjectUtils.isEmpty(registerWay)) { + try { + int registerWayInt = Integer.parseInt(registerWay); + deviceChannel.setRegisterWay(registerWayInt); + }catch (NumberFormatException exception) { + logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); + deviceChannel.setRegisterWay(1); + } + }else { + deviceChannel.setRegisterWay(1); + } + + // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式 + String safetyWay = getText(itemDevice, "SafetyWay"); + if (!ObjectUtils.isEmpty(safetyWay)) { + try { + deviceChannel.setSafetyWay(Integer.parseInt(safetyWay)); + }catch (NumberFormatException e) { + logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay); + } + } + + // 证书序列号(有证书的设备必选) + String certNum = getText(itemDevice, "CertNum"); + if (!ObjectUtils.isEmpty(certNum)) { + deviceChannel.setCertNum(certNum); + } + + // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效 + String certifiable = getText(itemDevice, "Certifiable"); + if (!ObjectUtils.isEmpty(certifiable)) { + try { + deviceChannel.setCertifiable(Integer.parseInt(certifiable)); + }catch (NumberFormatException e) { + logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable); + } + } + + // 无效原因码(有证书且证书无效的设备必选) + String errCode = getText(itemDevice, "ErrCode"); + if (!ObjectUtils.isEmpty(errCode)) { + try { + deviceChannel.setErrCode(Integer.parseInt(errCode)); + }catch (NumberFormatException e) { + logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode); + } + } + + // 证书终止有效期(有证书的设备必选) + String endTime = getText(itemDevice, "EndTime"); + if (!ObjectUtils.isEmpty(endTime)) { + deviceChannel.setEndTime(endTime); + } + + + // 设备/区域/系统IP地址 + String ipAddress = getText(itemDevice, "IPAddress"); + if (!ObjectUtils.isEmpty(ipAddress)) { + deviceChannel.setIpAddress(ipAddress); + } + + // 设备/区域/系统端口 + String port = getText(itemDevice, "Port"); + if (!ObjectUtils.isEmpty(port)) { + try { + deviceChannel.setPort(Integer.parseInt(port)); + }catch (NumberFormatException e) { + logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port); + } + } + + // 设备口令 + String password = getText(itemDevice, "Password"); + if (!ObjectUtils.isEmpty(password)) { + deviceChannel.setPassword(password); + } + + + // 设备状态 + String status = getText(itemDevice, "Status"); + if (status != null) { + // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 + if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) { + deviceChannel.setStatus(true); + } + if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { + deviceChannel.setStatus(false); + } + }else { + deviceChannel.setStatus(true); + } + + // 经度 + String longitude = getText(itemDevice, "Longitude"); + if (NumericUtil.isDouble(longitude)) { + deviceChannel.setLongitude(Double.parseDouble(longitude)); + } else { + deviceChannel.setLongitude(0.00); + } + + // 纬度 + String latitude = getText(itemDevice, "Latitude"); + if (NumericUtil.isDouble(latitude)) { + deviceChannel.setLatitude(Double.parseDouble(latitude)); + } else { + deviceChannel.setLatitude(0.00); + } + + deviceChannel.setGpsTime(DateUtil.getNow()); + + // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选 + String ptzType = getText(itemDevice, "PTZType"); + if (ObjectUtils.isEmpty(ptzType)) { + //兼容INFO中的信息 + Element info = itemDevice.element("Info"); + String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType"); + if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){ + try { + deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo)); + }catch (NumberFormatException e){ + logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo); + } + } + } else { + try { + deviceChannel.setPTZType(Integer.parseInt(ptzType)); + }catch (NumberFormatException e){ + logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType); + } + } + + // TODO 摄像机位置类型扩展。 + // 1-省际检查站、 + // 2-党政机关、 + // 3-车站码头、 + // 4-中心广场、 + // 5-体育场馆、 + // 6-商业中心、 + // 7-宗教场所、 + // 8-校园周边、 + // 9-治安复杂区域、 + // 10-交通干线。 + // String positionType = getText(itemDevice, "PositionType"); + + // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。 + // String roomType = getText(itemDevice, "RoomType"); + // TODO 摄像机用途属性 + // String useType = getText(itemDevice, "UseType"); + // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光 + // String supplyLightType = getText(itemDevice, "SupplyLightType"); + // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。 + // String directionType = getText(itemDevice, "DirectionType"); + // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定 + // String resolution = getText(itemDevice, "Resolution"); + + // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4 + // String downloadSpeed = getText(itemDevice, "DownloadSpeed"); + // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层) + // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode"); + // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强 + // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode"); + + + deviceChannel.setSecrecy(secrecy); + break; + } + } + + return deviceChannel; + } + + /** + * 新增方法支持内部嵌套 + * + * @param element xmlElement + * @param clazz 结果类 + * @param 泛型 + * @return 结果对象 + * @throws NoSuchMethodException + * @throws InvocationTargetException + * @throws InstantiationException + * @throws IllegalAccessException + */ + public static T loadElement(Element element, Class clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + Field[] fields = clazz.getDeclaredFields(); + T t = clazz.getDeclaredConstructor().newInstance(); + for (Field field : fields) { + ReflectionUtils.makeAccessible(field); + MessageElement annotation = field.getAnnotation(MessageElement.class); + if (annotation == null) { + continue; + } + String value = annotation.value(); + String subVal = annotation.subVal(); + Element element1 = element.element(value); + if (element1 == null) { + continue; + } + if ("".equals(subVal)) { + // 无下级数据 + Object fieldVal = element1.isTextOnly() ? element1.getText() : loadElement(element1, field.getType()); + Object o = simpleTypeDeal(field.getType(), fieldVal); + ReflectionUtils.setField(field, t, o); + } else { + // 存在下级数据 + ArrayList list = new ArrayList<>(); + Type genericType = field.getGenericType(); + if (!(genericType instanceof ParameterizedType)) { + continue; + } + Class aClass = (Class) ((ParameterizedType) genericType).getActualTypeArguments()[0]; + for (Element element2 : element1.elements(subVal)) { + list.add(loadElement(element2, aClass)); + } + ReflectionUtils.setField(field, t, list); + } + } + return t; + } + + /** + * 简单类型处理 + * + * @param tClass + * @param val + * @return + */ + private static Object simpleTypeDeal(Class tClass, Object val) { + if (tClass.equals(String.class)) { + return val.toString(); + } + if (tClass.equals(Integer.class)) { + return Integer.valueOf(val.toString()); + } + if (tClass.equals(Double.class)) { + return Double.valueOf(val.toString()); + } + if (tClass.equals(Long.class)) { + return Long.valueOf(val.toString()); + } + return val; + } } \ No newline at end of file diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java old mode 100644 new mode 100755 index 3c8f2de2..880152fa --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -1,777 +1,777 @@ -package com.genersoft.iot.vmp.media.zlm; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; -import com.genersoft.iot.vmp.common.InviteInfo; -import com.genersoft.iot.vmp.common.InviteSessionType; -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.common.VideoManagerConstants; -import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; -import com.genersoft.iot.vmp.gb28181.bean.*; -import com.genersoft.iot.vmp.gb28181.event.EventPublisher; -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; -import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; -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.impl.SIPCommanderFroPlatform; -import com.genersoft.iot.vmp.media.zlm.dto.HookType; -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; -import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; -import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; -import com.genersoft.iot.vmp.media.zlm.dto.hook.*; -import com.genersoft.iot.vmp.service.*; -import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; -import com.genersoft.iot.vmp.service.bean.SSRCInfo; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.storager.IVideoManagerStorage; -import com.genersoft.iot.vmp.utils.DateUtil; -import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; -import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo; -import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo; -import com.genersoft.iot.vmp.vmanager.bean.StreamContent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import org.springframework.util.ObjectUtils; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.context.request.async.DeferredResult; - -import javax.servlet.http.HttpServletRequest; -import javax.sip.InvalidArgumentException; -import javax.sip.SipException; -import java.text.ParseException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -/** - * @description:针对 ZLMediaServer的hook事件监听 - * @author: swwheihei - * @date: 2020年5月8日 上午10:46:48 - */ -@RestController -@RequestMapping("/index/hook") -public class ZLMHttpHookListener { - - private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class); - - @Autowired - private SIPCommander cmder; - - @Autowired - private SIPCommanderFroPlatform commanderFroPlatform; - - @Autowired - private IPlayService playService; - - @Autowired - private IVideoManagerStorage storager; - - @Autowired - private IRedisCatchStorage redisCatchStorage; - - @Autowired - private IInviteStreamService inviteStreamService; - - @Autowired - private IDeviceService deviceService; - - @Autowired - private IMediaServerService mediaServerService; - - @Autowired - private IStreamProxyService streamProxyService; - - @Autowired - private DeferredResultHolder resultHolder; - - @Autowired - private IMediaService mediaService; - - @Autowired - private EventPublisher eventPublisher; - - @Autowired - private ZLMMediaListManager zlmMediaListManager; - - @Autowired - private ZlmHttpHookSubscribe subscribe; - - @Autowired - private UserSetting userSetting; - - @Autowired - private IUserService userService; - - @Autowired - private VideoStreamSessionManager sessionManager; - - @Autowired - private AssistRESTfulUtils assistRESTfulUtils; - - @Autowired - private SSRCFactory ssrcFactory; - - @Qualifier("taskExecutor") - @Autowired - private ThreadPoolTaskExecutor taskExecutor; - - @Autowired - private RedisTemplate redisTemplate; - - /** - * 服务器定时上报时间,上报间隔可配置,默认10s上报一次 - */ - @ResponseBody - - @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8") - public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) { - - - taskExecutor.execute(() -> { - List subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive); - if (subscribes != null && subscribes.size() > 0) { - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { - subscribe.response(null, param); - } - } - }); - mediaServerService.updateMediaServerKeepalive(param.getMediaServerId(), param.getData()); - - return HookResult.SUCCESS(); - } - - /** - * 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。 - */ - @ResponseBody - - @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); - } - String mediaServerId = param.getMediaServerId(); - - taskExecutor.execute(() -> { - JSONObject json = (JSONObject) JSON.toJSON(param); - ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json); - if (subscribe != null) { - MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); - if (mediaInfo != null) { - subscribe.response(mediaInfo, param); - } - } - }); - if (!"rtp".equals(param.getApp())) { - Map paramMap = urlParamToMap(param.getParams()); - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); - if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) { - return new HookResult(401, "Unauthorized"); - } - } - - return HookResult.SUCCESS(); - } - - /** - * rtsp/rtmp/rtp推流鉴权事件。 - */ - @ResponseBody - @PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8") - public HookResultForOnPublish onPublish(@RequestBody OnPublishHookParam param) { - - JSONObject json = (JSONObject) JSON.toJSON(param); - - logger.info("[ZLM HOOK]推流鉴权:{}->{}", param.getMediaServerId(), param); - - String mediaServerId = json.getString("mediaServerId"); - MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); - if (mediaInfo == null) { - return new HookResultForOnPublish(200, "success"); - } - // 推流鉴权的处理 - if (!"rtp".equals(param.getApp())) { - if (userSetting.getPushAuthority()) { - // 推流鉴权 - if (param.getParams() == null) { - logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)"); - return new HookResultForOnPublish(401, "Unauthorized"); - } - Map paramMap = urlParamToMap(param.getParams()); - String sign = paramMap.get("sign"); - if (sign == null) { - logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)"); - return new HookResultForOnPublish(401, "Unauthorized"); - } - // 推流自定义播放鉴权码 - String callId = paramMap.get("callId"); - // 鉴权配置 - boolean hasAuthority = userService.checkPushAuthority(callId, sign); - if (!hasAuthority) { - logger.info("推流鉴权失败: sign 无权限: callId={}. sign={}", callId, sign); - return new HookResultForOnPublish(401, "Unauthorized"); - } - StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); - streamAuthorityInfo.setCallId(callId); - streamAuthorityInfo.setSign(sign); - // 鉴权通过 - redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); - // 通知assist新的callId - if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) { - taskExecutor.execute(() -> { - assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null); - }); - } - } - } else { - zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId()); - } - - - HookResultForOnPublish result = HookResultForOnPublish.SUCCESS(); - result.setEnable_audio(true); - 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"); - } - } - }); - - // 是否录像 - if ("rtp".equals(param.getApp())) { - result.setEnable_mp4(userSetting.getRecordSip()); - } else { - result.setEnable_mp4(userSetting.isRecordPushLive()); - } - // 替换流地址 - if ("rtp".equals(param.getApp()) && !mediaInfo.isRtpEnable()) { - String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));; - InviteInfo inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc); - if (inviteInfo != null) { - result.setStream_replace(inviteInfo.getStream()); - logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream()); - } - } - List ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream()); - if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { - String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); - String channelId = ssrcTransactionForAll.get(0).getChannelId(); - DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); - if (deviceChannel != null) { - result.setEnable_audio(deviceChannel.isHasAudio()); - } - // 如果是录像下载就设置视频间隔十秒 - if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) { - result.setMp4_max_second(10); - result.setEnable_mp4(true); - } - } - if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) { - logger.info("推流时发现尚未设置录像路径,从assist服务中读取"); - JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null); - if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) { - JSONObject dataJson = info.getJSONObject("data"); - if (dataJson != null) { - String recordPath = dataJson.getString("record"); - userSetting.setRecordPath(recordPath); - result.setMp4_save_path(recordPath); - // 修改zlm中的录像路径 - if (mediaInfo.isAutoConfig()) { - taskExecutor.execute(() -> { - mediaServerService.setZLMConfig(mediaInfo, false); - }); - } - } - } - } - if (param.getApp().equalsIgnoreCase("rtp")) { - String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + param.getStream(); - OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(receiveKey); - - String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + param.getStream(); - OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo)redisTemplate.opsForValue().get(receiveKeyForPS); - if (otherRtpSendInfo != null || otherPsSendInfo != null) { - result.setEnable_mp4(true); - } - } - logger.info("[ZLM HOOK]推流鉴权 响应:{}->{}->>>>{}", param.getMediaServerId(), param, result); - return result; - } - - - /** - * rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。 - */ - @ResponseBody - @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") - public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) { - - if (param.isRegist()) { - logger.info("[ZLM HOOK] 流注册, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); - } else { - logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); - } - - - JSONObject json = (JSONObject) JSON.toJSON(param); - taskExecutor.execute(() -> { - ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json); - MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); - if (mediaInfo == null) { - logger.info("[ZLM HOOK] 流变化未找到ZLM, {}", param.getMediaServerId()); - return; - } - if (subscribe != null) { - subscribe.response(mediaInfo, param); - } - - List tracks = param.getTracks(); - // TODO 重构此处逻辑 - boolean isPush = false; - if (param.isRegist()) { - // 处理流注册的鉴权信息 - if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() - || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() - || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { - isPush = true; - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); - if (streamAuthorityInfo == null) { - streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); - } else { - streamAuthorityInfo.setOriginType(param.getOriginType()); - streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr()); - } - redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); - } - } else { - redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream()); - } - - if ("rtsp".equals(param.getSchema())) { - // 更新流媒体负载信息 - if (param.isRegist()) { - mediaServerService.addCount(param.getMediaServerId()); - } else { - mediaServerService.removeCount(param.getMediaServerId()); - } - // 设置拉流代理上线/离线 - int updateStatusResult = streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream()); - if (updateStatusResult > 0) { - - } - - if ("rtp".equals(param.getApp()) && !param.isRegist()) { - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream()); - if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) { - inviteStreamService.removeInviteInfo(inviteInfo); - storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId()); - } - } else { - if (!"rtp".equals(param.getApp())) { - String type = OriginType.values()[param.getOriginType()].getType(); - if (param.isRegist()) { - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo( - param.getApp(), param.getStream()); - String callId = null; - if (streamAuthorityInfo != null) { - callId = streamAuthorityInfo.getCallId(); - } - StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo, - param.getApp(), param.getStream(), tracks, callId); - param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); - redisCatchStorage.addStream(mediaInfo, type, param.getApp(), param.getStream(), param); - if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() - || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() - || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { - param.setSeverId(userSetting.getServerId()); - zlmMediaListManager.addPush(param); - } - } else { - // 兼容流注销时类型从redis记录获取 - OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo( - param.getApp(), param.getStream(), param.getMediaServerId()); - if (onStreamChangedHookParam != null) { - type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType(); - redisCatchStorage.removeStream(mediaInfo.getId(), type, param.getApp(), param.getStream()); - } - GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); - if (gbStream != null) { -// eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); - } - zlmMediaListManager.removeMedia(param.getApp(), param.getStream()); - } - GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); - if (gbStream != null) { - if (userSetting.isUsePushingAsStatus()) { - eventPublisher.catalogEventPublishForStream(null, gbStream, param.isRegist()?CatalogEvent.ON:CatalogEvent.OFF); - } - } - if (type != null) { - // 发送流变化redis消息 - JSONObject jsonObject = new JSONObject(); - jsonObject.put("serverId", userSetting.getServerId()); - jsonObject.put("app", param.getApp()); - jsonObject.put("stream", param.getStream()); - jsonObject.put("register", param.isRegist()); - jsonObject.put("mediaServerId", param.getMediaServerId()); - redisCatchStorage.sendStreamChangeMsg(type, jsonObject); - } - } - } - if (!param.isRegist()) { - List sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); - if (sendRtpItems.size() > 0) { - for (SendRtpItem sendRtpItem : sendRtpItems) { - if (sendRtpItem != null && sendRtpItem.getApp().equals(param.getApp())) { - String platformId = sendRtpItem.getPlatformId(); - ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); - Device device = deviceService.getDevice(platformId); - - try { - if (platform != null) { - commanderFroPlatform.streamByeCmd(platform, sendRtpItem); - redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(), - sendRtpItem.getCallId(), sendRtpItem.getStreamId()); - } else { - cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId()); - } - } catch (SipException | InvalidArgumentException | ParseException | - SsrcTransactionNotFoundException e) { - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); - } - } - } - } - } - } - }); - - return HookResult.SUCCESS(); - } - - /** - * 流无人观看时事件,用户可以通过此事件选择是否关闭无人看的流。 - */ - @ResponseBody - @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") - public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) { - - logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), - param.getApp(), param.getStream()); - JSONObject ret = new JSONObject(); - ret.put("code", 0); - // 国标类型的流 - if ("rtp".equals(param.getApp())) { - ret.put("close", userSetting.getStreamOnDemand()); - // 国标流, 点播/录像回放/录像下载 - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream()); - // 点播 - if (inviteInfo != null) { - // 录像下载 - if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) { - ret.put("close", false); - return ret; - } - // 收到无人观看说明流也没有在往上级推送 - if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) { - List sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId( - inviteInfo.getChannelId()); - if (sendRtpItems.size() > 0) { - for (SendRtpItem sendRtpItem : sendRtpItems) { - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); - try { - commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); - } catch (SipException | InvalidArgumentException | ParseException e) { - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); - } - redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), - sendRtpItem.getCallId(), sendRtpItem.getStreamId()); - if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) { - MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, - sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(), - sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId()); - messageForPushChannel.setPlatFormIndex(parentPlatform.getId()); - redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel); - } - } - } - } - Device device = deviceService.getDevice(inviteInfo.getDeviceId()); - if (device != null) { - try { - // 多查询一次防止已经被处理了 - InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(), - inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()); - if (info != null) { - cmder.streamByeCmd(device, inviteInfo.getChannelId(), - inviteInfo.getStream(), null); - } - } catch (InvalidArgumentException | ParseException | SipException | - SsrcTransactionNotFoundException e) { - logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage()); - } - } - - inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), - inviteInfo.getChannelId(), inviteInfo.getStream()); - storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId()); - return ret; - } - } else { - // 非国标流 推流/拉流代理 - // 拉流代理 - StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); - if (streamProxyItem != null) { - if (streamProxyItem.isEnableRemoveNoneReader()) { - // 无人观看自动移除 - ret.put("close", true); - streamProxyService.del(param.getApp(), param.getStream()); - String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl(); - logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url); - } else if (streamProxyItem.isEnableDisableNoneReader()) { - // 无人观看停用 - ret.put("close", true); - // 修改数据 - streamProxyService.stop(param.getApp(), param.getStream()); - } else { - // 无人观看不做处理 - ret.put("close", false); - } - return ret; - } - // TODO 推流具有主动性,暂时不做处理 -// StreamPushItem streamPushItem = streamPushService.getPush(app, streamId); -// if (streamPushItem != null) { -// // TODO 发送停止 -// -// } - } - return ret; - } - - /** - * 流未找到事件,用户可以在此事件触发时,立即去拉流,这样可以实现按需拉流;此事件对回复不敏感。 - */ - @ResponseBody - @PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8") - public DeferredResult onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) { - logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); - - DeferredResult defaultResult = new DeferredResult<>(); - - MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); - if (!userSetting.isAutoApplyPlay() || mediaInfo == null) { - defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); - return defaultResult; - } - - if ("rtp".equals(param.getApp())) { - String[] s = param.getStream().split("_"); - if ((s.length != 2 && s.length != 4)) { - defaultResult.setResult(HookResult.SUCCESS()); - return defaultResult; - } - String deviceId = s[0]; - String channelId = s[1]; - Device device = redisCatchStorage.getDevice(deviceId); - if (device == null) { - defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); - return defaultResult; - } - DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); - if (deviceChannel == null) { - defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); - return defaultResult; - } - if (s.length == 2) { - logger.info("[ZLM HOOK] 预览流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); - - RequestMessage msg = new RequestMessage(); - String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; - boolean exist = resultHolder.exist(key, null); - msg.setKey(key); - String uuid = UUID.randomUUID().toString(); - msg.setId(uuid); - DeferredResult result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); - - result.onTimeout(() -> { - logger.info("[ZLM HOOK] 预览流自动点播, 等待超时"); - msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); - resultHolder.invokeResult(msg); - }); - - resultHolder.put(key, uuid, result); - - if (!exist) { - playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> { - msg.setData(new HookResult(code, message)); - resultHolder.invokeResult(msg); - }); - } - return result; - }else if(s.length == 4){ - // 此时为录像回放, 录像回放格式为> 设备ID_通道ID_开始时间_结束时间 - String startTimeStr = s[2]; - String endTimeStr = s[3]; - if (startTimeStr == null || endTimeStr == null || startTimeStr.length() != 14 || endTimeStr.length() != 14) { - defaultResult.setResult(HookResult.SUCCESS()); - return defaultResult; - } - String startTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(startTimeStr); - String endTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(endTimeStr); - logger.info("[ZLM HOOK] 回放流未找到, 发起自动点播:{}->{}->{}/{}-{}-{}", - param.getMediaServerId(), param.getSchema(), - param.getApp(), param.getStream(), - startTime, endTime - ); - RequestMessage msg = new RequestMessage(); - String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId; - boolean exist = resultHolder.exist(key, null); - msg.setKey(key); - String uuid = UUID.randomUUID().toString(); - msg.setId(uuid); - DeferredResult result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); - - result.onTimeout(() -> { - logger.info("[ZLM HOOK] 回放流自动点播, 等待超时"); - // 释放rtpserver - msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); - resultHolder.invokeResult(msg); - }); - - resultHolder.put(key, uuid, result); - - if (!exist) { - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaInfo, param.getStream(), null, - device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); - playService.playBack(mediaInfo, ssrcInfo, deviceId, channelId, startTime, endTime, (code, message, data) -> { - msg.setData(new HookResult(code, message)); - resultHolder.invokeResult(msg); - }); - } - return result; - }else { - defaultResult.setResult(HookResult.SUCCESS()); - return defaultResult; - } - - } else { - // 拉流代理 - StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); - if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) { - streamProxyService.start(param.getApp(), param.getStream()); - } - DeferredResult result = new DeferredResult<>(); - result.setResult(HookResult.SUCCESS()); - return result; - } - } - - /** - * 服务器启动事件,可以用于监听服务器崩溃重启;此事件对回复不敏感。 - */ - @ResponseBody - @PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8") - public HookResult onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject) { - - jsonObject.put("ip", request.getRemoteAddr()); - ZLMServerConfig zlmServerConfig = JSON.to(ZLMServerConfig.class, jsonObject); - zlmServerConfig.setIp(request.getRemoteAddr()); - logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId()); - taskExecutor.execute(() -> { - List subscribes = this.subscribe.getSubscribes(HookType.on_server_started); - if (subscribes != null && subscribes.size() > 0) { - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { - subscribe.response(null, zlmServerConfig); - } - } - mediaServerService.zlmServerOnline(zlmServerConfig); - }); - - return HookResult.SUCCESS(); - } - - /** - * 发送rtp(startSendRtp)被动关闭时回调 - */ - @ResponseBody - @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8") - public HookResult onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param) { - - logger.info("[ZLM HOOK] rtp发送关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream()); - - // 查找对应的上级推流,发送停止 - if (!"rtp".equals(param.getApp())) { - return HookResult.SUCCESS(); - } - taskExecutor.execute(() -> { - List sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); - if (sendRtpItems.size() > 0) { - for (SendRtpItem sendRtpItem : sendRtpItems) { - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); - ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc()); - try { - commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); - } catch (SipException | InvalidArgumentException | ParseException e) { - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); - } - redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), - sendRtpItem.getCallId(), sendRtpItem.getStreamId()); - } - } - }); - - return HookResult.SUCCESS(); - } - - /** - * rtpServer收流超时 - */ - @ResponseBody - @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8") - public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam param) { - logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc()); - - taskExecutor.execute(() -> { - JSONObject json = (JSONObject) JSON.toJSON(param); - List subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); - if (subscribes != null && subscribes.size() > 0) { - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { - subscribe.response(null, param); - } - } - }); - - return HookResult.SUCCESS(); - } - - private Map urlParamToMap(String params) { - HashMap map = new HashMap<>(); - if (ObjectUtils.isEmpty(params)) { - return map; - } - String[] paramsArray = params.split("&"); - if (paramsArray.length == 0) { - return map; - } - for (String param : paramsArray) { - String[] paramArray = param.split("="); - if (paramArray.length == 2) { - map.put(paramArray[0], paramArray[1]); - } - } - return map; - } -} +package com.genersoft.iot.vmp.media.zlm; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.common.InviteInfo; +import com.genersoft.iot.vmp.common.InviteSessionType; +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; +import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; +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.impl.SIPCommanderFroPlatform; +import com.genersoft.iot.vmp.media.zlm.dto.HookType; +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; +import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; +import com.genersoft.iot.vmp.media.zlm.dto.hook.*; +import com.genersoft.iot.vmp.service.*; +import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; +import com.genersoft.iot.vmp.service.bean.SSRCInfo; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import com.genersoft.iot.vmp.storager.IVideoManagerStorage; +import com.genersoft.iot.vmp.utils.DateUtil; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo; +import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo; +import com.genersoft.iot.vmp.vmanager.bean.StreamContent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.util.ObjectUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.async.DeferredResult; + +import javax.servlet.http.HttpServletRequest; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * @description:针对 ZLMediaServer的hook事件监听 + * @author: swwheihei + * @date: 2020年5月8日 上午10:46:48 + */ +@RestController +@RequestMapping("/index/hook") +public class ZLMHttpHookListener { + + private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class); + + @Autowired + private SIPCommander cmder; + + @Autowired + private SIPCommanderFroPlatform commanderFroPlatform; + + @Autowired + private IPlayService playService; + + @Autowired + private IVideoManagerStorage storager; + + @Autowired + private IRedisCatchStorage redisCatchStorage; + + @Autowired + private IInviteStreamService inviteStreamService; + + @Autowired + private IDeviceService deviceService; + + @Autowired + private IMediaServerService mediaServerService; + + @Autowired + private IStreamProxyService streamProxyService; + + @Autowired + private DeferredResultHolder resultHolder; + + @Autowired + private IMediaService mediaService; + + @Autowired + private EventPublisher eventPublisher; + + @Autowired + private ZLMMediaListManager zlmMediaListManager; + + @Autowired + private ZlmHttpHookSubscribe subscribe; + + @Autowired + private UserSetting userSetting; + + @Autowired + private IUserService userService; + + @Autowired + private VideoStreamSessionManager sessionManager; + + @Autowired + private AssistRESTfulUtils assistRESTfulUtils; + + @Autowired + private SSRCFactory ssrcFactory; + + @Qualifier("taskExecutor") + @Autowired + private ThreadPoolTaskExecutor taskExecutor; + + @Autowired + private RedisTemplate redisTemplate; + + /** + * 服务器定时上报时间,上报间隔可配置,默认10s上报一次 + */ + @ResponseBody + + @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8") + public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) { + + + taskExecutor.execute(() -> { + List subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive); + if (subscribes != null && subscribes.size() > 0) { + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { + subscribe.response(null, param); + } + } + }); + mediaServerService.updateMediaServerKeepalive(param.getMediaServerId(), param.getData()); + + return HookResult.SUCCESS(); + } + + /** + * 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。 + */ + @ResponseBody + + @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); + } + String mediaServerId = param.getMediaServerId(); + + taskExecutor.execute(() -> { + JSONObject json = (JSONObject) JSON.toJSON(param); + ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json); + if (subscribe != null) { + MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); + if (mediaInfo != null) { + subscribe.response(mediaInfo, param); + } + } + }); + if (!"rtp".equals(param.getApp())) { + Map paramMap = urlParamToMap(param.getParams()); + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); + if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) { + return new HookResult(401, "Unauthorized"); + } + } + + return HookResult.SUCCESS(); + } + + /** + * rtsp/rtmp/rtp推流鉴权事件。 + */ + @ResponseBody + @PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8") + public HookResultForOnPublish onPublish(@RequestBody OnPublishHookParam param) { + + JSONObject json = (JSONObject) JSON.toJSON(param); + + logger.info("[ZLM HOOK]推流鉴权:{}->{}", param.getMediaServerId(), param); + + String mediaServerId = json.getString("mediaServerId"); + MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); + if (mediaInfo == null) { + return new HookResultForOnPublish(200, "success"); + } + // 推流鉴权的处理 + if (!"rtp".equals(param.getApp())) { + if (userSetting.getPushAuthority()) { + // 推流鉴权 + if (param.getParams() == null) { + logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)"); + return new HookResultForOnPublish(401, "Unauthorized"); + } + Map paramMap = urlParamToMap(param.getParams()); + String sign = paramMap.get("sign"); + if (sign == null) { + logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)"); + return new HookResultForOnPublish(401, "Unauthorized"); + } + // 推流自定义播放鉴权码 + String callId = paramMap.get("callId"); + // 鉴权配置 + boolean hasAuthority = userService.checkPushAuthority(callId, sign); + if (!hasAuthority) { + logger.info("推流鉴权失败: sign 无权限: callId={}. sign={}", callId, sign); + return new HookResultForOnPublish(401, "Unauthorized"); + } + StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); + streamAuthorityInfo.setCallId(callId); + streamAuthorityInfo.setSign(sign); + // 鉴权通过 + redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); + // 通知assist新的callId + if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) { + taskExecutor.execute(() -> { + assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null); + }); + } + } + } else { + zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId()); + } + + + HookResultForOnPublish result = HookResultForOnPublish.SUCCESS(); + result.setEnable_audio(true); + 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"); + } + } + }); + + // 是否录像 + if ("rtp".equals(param.getApp())) { + result.setEnable_mp4(userSetting.getRecordSip()); + } else { + result.setEnable_mp4(userSetting.isRecordPushLive()); + } + // 替换流地址 + if ("rtp".equals(param.getApp()) && !mediaInfo.isRtpEnable()) { + String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));; + InviteInfo inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc); + if (inviteInfo != null) { + result.setStream_replace(inviteInfo.getStream()); + logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream()); + } + } + List ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream()); + if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { + String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); + String channelId = ssrcTransactionForAll.get(0).getChannelId(); + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); + if (deviceChannel != null) { + result.setEnable_audio(deviceChannel.isHasAudio()); + } + // 如果是录像下载就设置视频间隔十秒 + if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) { + result.setMp4_max_second(10); + result.setEnable_mp4(true); + } + } + if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) { + logger.info("推流时发现尚未设置录像路径,从assist服务中读取"); + JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null); + if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) { + JSONObject dataJson = info.getJSONObject("data"); + if (dataJson != null) { + String recordPath = dataJson.getString("record"); + userSetting.setRecordPath(recordPath); + result.setMp4_save_path(recordPath); + // 修改zlm中的录像路径 + if (mediaInfo.isAutoConfig()) { + taskExecutor.execute(() -> { + mediaServerService.setZLMConfig(mediaInfo, false); + }); + } + } + } + } + if (param.getApp().equalsIgnoreCase("rtp")) { + String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + param.getStream(); + OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(receiveKey); + + String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + param.getStream(); + OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo)redisTemplate.opsForValue().get(receiveKeyForPS); + if (otherRtpSendInfo != null || otherPsSendInfo != null) { + result.setEnable_mp4(true); + } + } + logger.info("[ZLM HOOK]推流鉴权 响应:{}->{}->>>>{}", param.getMediaServerId(), param, result); + return result; + } + + + /** + * rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。 + */ + @ResponseBody + @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") + public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) { + + if (param.isRegist()) { + logger.info("[ZLM HOOK] 流注册, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); + } else { + logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); + } + + + JSONObject json = (JSONObject) JSON.toJSON(param); + taskExecutor.execute(() -> { + ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json); + MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); + if (mediaInfo == null) { + logger.info("[ZLM HOOK] 流变化未找到ZLM, {}", param.getMediaServerId()); + return; + } + if (subscribe != null) { + subscribe.response(mediaInfo, param); + } + + List tracks = param.getTracks(); + // TODO 重构此处逻辑 + boolean isPush = false; + if (param.isRegist()) { + // 处理流注册的鉴权信息 + if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() + || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() + || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { + isPush = true; + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); + if (streamAuthorityInfo == null) { + streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); + } else { + streamAuthorityInfo.setOriginType(param.getOriginType()); + streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr()); + } + redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); + } + } else { + redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream()); + } + + if ("rtsp".equals(param.getSchema())) { + // 更新流媒体负载信息 + if (param.isRegist()) { + mediaServerService.addCount(param.getMediaServerId()); + } else { + mediaServerService.removeCount(param.getMediaServerId()); + } + // 设置拉流代理上线/离线 + int updateStatusResult = streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream()); + if (updateStatusResult > 0) { + + } + + if ("rtp".equals(param.getApp()) && !param.isRegist()) { + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream()); + if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) { + inviteStreamService.removeInviteInfo(inviteInfo); + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId()); + } + } else { + if (!"rtp".equals(param.getApp())) { + String type = OriginType.values()[param.getOriginType()].getType(); + if (param.isRegist()) { + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo( + param.getApp(), param.getStream()); + String callId = null; + if (streamAuthorityInfo != null) { + callId = streamAuthorityInfo.getCallId(); + } + StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo, + param.getApp(), param.getStream(), tracks, callId); + param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); + redisCatchStorage.addStream(mediaInfo, type, param.getApp(), param.getStream(), param); + if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() + || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() + || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { + param.setSeverId(userSetting.getServerId()); + zlmMediaListManager.addPush(param); + } + } else { + // 兼容流注销时类型从redis记录获取 + OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo( + param.getApp(), param.getStream(), param.getMediaServerId()); + if (onStreamChangedHookParam != null) { + type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType(); + redisCatchStorage.removeStream(mediaInfo.getId(), type, param.getApp(), param.getStream()); + } + GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); + if (gbStream != null) { +// eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); + } + zlmMediaListManager.removeMedia(param.getApp(), param.getStream()); + } + GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); + if (gbStream != null) { + if (userSetting.isUsePushingAsStatus()) { + eventPublisher.catalogEventPublishForStream(null, gbStream, param.isRegist()?CatalogEvent.ON:CatalogEvent.OFF); + } + } + if (type != null) { + // 发送流变化redis消息 + JSONObject jsonObject = new JSONObject(); + jsonObject.put("serverId", userSetting.getServerId()); + jsonObject.put("app", param.getApp()); + jsonObject.put("stream", param.getStream()); + jsonObject.put("register", param.isRegist()); + jsonObject.put("mediaServerId", param.getMediaServerId()); + redisCatchStorage.sendStreamChangeMsg(type, jsonObject); + } + } + } + if (!param.isRegist()) { + List sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); + if (sendRtpItems.size() > 0) { + for (SendRtpItem sendRtpItem : sendRtpItems) { + if (sendRtpItem != null && sendRtpItem.getApp().equals(param.getApp())) { + String platformId = sendRtpItem.getPlatformId(); + ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); + Device device = deviceService.getDevice(platformId); + + try { + if (platform != null) { + commanderFroPlatform.streamByeCmd(platform, sendRtpItem); + redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(), + sendRtpItem.getCallId(), sendRtpItem.getStreamId()); + } else { + cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId()); + } + } catch (SipException | InvalidArgumentException | ParseException | + SsrcTransactionNotFoundException e) { + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); + } + } + } + } + } + } + }); + + return HookResult.SUCCESS(); + } + + /** + * 流无人观看时事件,用户可以通过此事件选择是否关闭无人看的流。 + */ + @ResponseBody + @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") + public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) { + + logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), + param.getApp(), param.getStream()); + JSONObject ret = new JSONObject(); + ret.put("code", 0); + // 国标类型的流 + if ("rtp".equals(param.getApp())) { + ret.put("close", userSetting.getStreamOnDemand()); + // 国标流, 点播/录像回放/录像下载 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream()); + // 点播 + if (inviteInfo != null) { + // 录像下载 + if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) { + ret.put("close", false); + return ret; + } + // 收到无人观看说明流也没有在往上级推送 + if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) { + List sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId( + inviteInfo.getChannelId()); + if (sendRtpItems.size() > 0) { + for (SendRtpItem sendRtpItem : sendRtpItems) { + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); + try { + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); + } + redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), + sendRtpItem.getCallId(), sendRtpItem.getStreamId()); + if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) { + MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, + sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(), + sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId()); + messageForPushChannel.setPlatFormIndex(parentPlatform.getId()); + redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel); + } + } + } + } + Device device = deviceService.getDevice(inviteInfo.getDeviceId()); + if (device != null) { + try { + // 多查询一次防止已经被处理了 + InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(), + inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()); + if (info != null) { + cmder.streamByeCmd(device, inviteInfo.getChannelId(), + inviteInfo.getStream(), null); + } + } catch (InvalidArgumentException | ParseException | SipException | + SsrcTransactionNotFoundException e) { + logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage()); + } + } + + inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), + inviteInfo.getChannelId(), inviteInfo.getStream()); + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId()); + return ret; + } + } else { + // 非国标流 推流/拉流代理 + // 拉流代理 + StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); + if (streamProxyItem != null) { + if (streamProxyItem.isEnableRemoveNoneReader()) { + // 无人观看自动移除 + ret.put("close", true); + streamProxyService.del(param.getApp(), param.getStream()); + String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl(); + logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url); + } else if (streamProxyItem.isEnableDisableNoneReader()) { + // 无人观看停用 + ret.put("close", true); + // 修改数据 + streamProxyService.stop(param.getApp(), param.getStream()); + } else { + // 无人观看不做处理 + ret.put("close", false); + } + return ret; + } + // TODO 推流具有主动性,暂时不做处理 +// StreamPushItem streamPushItem = streamPushService.getPush(app, streamId); +// if (streamPushItem != null) { +// // TODO 发送停止 +// +// } + } + return ret; + } + + /** + * 流未找到事件,用户可以在此事件触发时,立即去拉流,这样可以实现按需拉流;此事件对回复不敏感。 + */ + @ResponseBody + @PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8") + public DeferredResult onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) { + logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); + + DeferredResult defaultResult = new DeferredResult<>(); + + MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); + if (!userSetting.isAutoApplyPlay() || mediaInfo == null) { + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); + return defaultResult; + } + + if ("rtp".equals(param.getApp())) { + String[] s = param.getStream().split("_"); + if ((s.length != 2 && s.length != 4)) { + defaultResult.setResult(HookResult.SUCCESS()); + return defaultResult; + } + String deviceId = s[0]; + String channelId = s[1]; + Device device = redisCatchStorage.getDevice(deviceId); + if (device == null) { + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); + return defaultResult; + } + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); + if (deviceChannel == null) { + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); + return defaultResult; + } + if (s.length == 2) { + logger.info("[ZLM HOOK] 预览流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); + + RequestMessage msg = new RequestMessage(); + String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; + boolean exist = resultHolder.exist(key, null); + msg.setKey(key); + String uuid = UUID.randomUUID().toString(); + msg.setId(uuid); + DeferredResult result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); + + result.onTimeout(() -> { + logger.info("[ZLM HOOK] 预览流自动点播, 等待超时"); + msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); + resultHolder.invokeResult(msg); + }); + + resultHolder.put(key, uuid, result); + + if (!exist) { + playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> { + msg.setData(new HookResult(code, message)); + resultHolder.invokeResult(msg); + }); + } + return result; + }else if(s.length == 4){ + // 此时为录像回放, 录像回放格式为> 设备ID_通道ID_开始时间_结束时间 + String startTimeStr = s[2]; + String endTimeStr = s[3]; + if (startTimeStr == null || endTimeStr == null || startTimeStr.length() != 14 || endTimeStr.length() != 14) { + defaultResult.setResult(HookResult.SUCCESS()); + return defaultResult; + } + String startTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(startTimeStr); + String endTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(endTimeStr); + logger.info("[ZLM HOOK] 回放流未找到, 发起自动点播:{}->{}->{}/{}-{}-{}", + param.getMediaServerId(), param.getSchema(), + param.getApp(), param.getStream(), + startTime, endTime + ); + RequestMessage msg = new RequestMessage(); + String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId; + boolean exist = resultHolder.exist(key, null); + msg.setKey(key); + String uuid = UUID.randomUUID().toString(); + msg.setId(uuid); + DeferredResult result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); + + result.onTimeout(() -> { + logger.info("[ZLM HOOK] 回放流自动点播, 等待超时"); + // 释放rtpserver + msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); + resultHolder.invokeResult(msg); + }); + + resultHolder.put(key, uuid, result); + + if (!exist) { + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaInfo, param.getStream(), null, + device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); + playService.playBack(mediaInfo, ssrcInfo, deviceId, channelId, startTime, endTime, (code, message, data) -> { + msg.setData(new HookResult(code, message)); + resultHolder.invokeResult(msg); + }); + } + return result; + }else { + defaultResult.setResult(HookResult.SUCCESS()); + return defaultResult; + } + + } else { + // 拉流代理 + StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); + if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) { + streamProxyService.start(param.getApp(), param.getStream()); + } + DeferredResult result = new DeferredResult<>(); + result.setResult(HookResult.SUCCESS()); + return result; + } + } + + /** + * 服务器启动事件,可以用于监听服务器崩溃重启;此事件对回复不敏感。 + */ + @ResponseBody + @PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8") + public HookResult onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject) { + + jsonObject.put("ip", request.getRemoteAddr()); + ZLMServerConfig zlmServerConfig = JSON.to(ZLMServerConfig.class, jsonObject); + zlmServerConfig.setIp(request.getRemoteAddr()); + logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId()); + taskExecutor.execute(() -> { + List subscribes = this.subscribe.getSubscribes(HookType.on_server_started); + if (subscribes != null && subscribes.size() > 0) { + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { + subscribe.response(null, zlmServerConfig); + } + } + mediaServerService.zlmServerOnline(zlmServerConfig); + }); + + return HookResult.SUCCESS(); + } + + /** + * 发送rtp(startSendRtp)被动关闭时回调 + */ + @ResponseBody + @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8") + public HookResult onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param) { + + logger.info("[ZLM HOOK] rtp发送关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream()); + + // 查找对应的上级推流,发送停止 + if (!"rtp".equals(param.getApp())) { + return HookResult.SUCCESS(); + } + taskExecutor.execute(() -> { + List sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); + if (sendRtpItems.size() > 0) { + for (SendRtpItem sendRtpItem : sendRtpItems) { + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); + ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc()); + try { + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); + } catch (SipException | InvalidArgumentException | ParseException e) { + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); + } + redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), + sendRtpItem.getCallId(), sendRtpItem.getStreamId()); + } + } + }); + + return HookResult.SUCCESS(); + } + + /** + * rtpServer收流超时 + */ + @ResponseBody + @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8") + public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam param) { + logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc()); + + taskExecutor.execute(() -> { + JSONObject json = (JSONObject) JSON.toJSON(param); + List subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); + if (subscribes != null && subscribes.size() > 0) { + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { + subscribe.response(null, param); + } + } + }); + + return HookResult.SUCCESS(); + } + + private Map urlParamToMap(String params) { + HashMap map = new HashMap<>(); + if (ObjectUtils.isEmpty(params)) { + return map; + } + String[] paramsArray = params.split("&"); + if (paramsArray.length == 0) { + return map; + } + for (String param : paramsArray) { + String[] paramArray = param.split("="); + if (paramArray.length == 2) { + map.put(paramArray[0], paramArray[1]); + } + } + return map; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java old mode 100644 new mode 100755 index bec072c0..8c84133f --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java @@ -42,7 +42,7 @@ public class ZLMServerFactory { * @param tcpMode 0/null udp 模式,1 tcp 被动模式, 2 tcp 主动模式。 * @return */ - public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port, Boolean reUsePort, Integer tcpMode) { + public int createRTPServer(MediaServerItem mediaServerItem, String streamId, long ssrc, Integer port, Boolean reUsePort, Integer tcpMode) { int result = -1; // 查询此rtp server 是否已经存在 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId); diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ChannelOnlineEvent.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ChannelOnlineEvent.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRtpServerTimeout.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRtpServerTimeout.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForServerStarted.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForServerStarted.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamChange.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamChange.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookType.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookType.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IHookSubscribe.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IHookSubscribe.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ServerKeepaliveData.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ServerKeepaliveData.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamAuthorityInfo.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamAuthorityInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMRunInfo.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMRunInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPlayHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPlayHookParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPublishHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPublishHookParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRtpServerTimeoutHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRtpServerTimeoutHookParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnSendRtpStoppedHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnSendRtpStoppedHookParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnServerKeepaliveHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnServerKeepaliveHookParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNoneReaderHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNoneReaderHookParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNotFoundHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNotFoundHookParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OriginType.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OriginType.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMEventAbstract.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMEventAbstract.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOfflineEvent.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOfflineEvent.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOnlineEvent.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOnlineEvent.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IDeviceAlarmService.java b/src/main/java/com/genersoft/iot/vmp/service/IDeviceAlarmService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java b/src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java b/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java b/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java b/src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/ILogService.java b/src/main/java/com/genersoft/iot/vmp/service/ILogService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java old mode 100644 new mode 100755 index 530cd6df..8cfdd88f --- a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData; import com.genersoft.iot.vmp.service.bean.MediaServerLoad; import com.genersoft.iot.vmp.service.bean.SSRCInfo; +import com.genersoft.iot.vmp.vmanager.bean.RecordFile; import java.util.List; @@ -93,4 +94,14 @@ public interface IMediaServerService { * @return */ MediaServerLoad getLoad(MediaServerItem mediaServerItem); + + /** + * 按时间查找录像文件 + */ + List getRecords(String app, String stream, String startTime, String endTime, List mediaServerItems); + + /** + * 查找存在录像文件的时间 + */ + List getRecordDates(String app, String stream, int year, int month, List mediaServerItems); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/IMediaService.java b/src/main/java/com/genersoft/iot/vmp/service/IMediaService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlatformChannelService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlatformChannelService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IRoleService.java b/src/main/java/com/genersoft/iot/vmp/service/IRoleService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java b/src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java b/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/IUserService.java b/src/main/java/com/genersoft/iot/vmp/service/IUserService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/ErrorCallback.java b/src/main/java/com/genersoft/iot/vmp/service/bean/ErrorCallback.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java b/src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java b/src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/InviteTimeOutCallback.java b/src/main/java/com/genersoft/iot/vmp/service/bean/InviteTimeOutCallback.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/MediaServerLoad.java b/src/main/java/com/genersoft/iot/vmp/service/bean/MediaServerLoad.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/MessageForPushChannel.java b/src/main/java/com/genersoft/iot/vmp/service/bean/MessageForPushChannel.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/MessageForPushChannelResponse.java b/src/main/java/com/genersoft/iot/vmp/service/bean/MessageForPushChannelResponse.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java b/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java b/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/PushStreamStatusChangeFromRedisDto.java b/src/main/java/com/genersoft/iot/vmp/service/bean/PushStreamStatusChangeFromRedisDto.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/RequestPushStreamMsg.java b/src/main/java/com/genersoft/iot/vmp/service/bean/RequestPushStreamMsg.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/RequestSendItemMsg.java b/src/main/java/com/genersoft/iot/vmp/service/bean/RequestSendItemMsg.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/ResponseSendItemMsg.java b/src/main/java/com/genersoft/iot/vmp/service/bean/ResponseSendItemMsg.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java b/src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/StreamPushItemFromRedis.java b/src/main/java/com/genersoft/iot/vmp/service/bean/StreamPushItemFromRedis.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/ThirdPartyGB.java b/src/main/java/com/genersoft/iot/vmp/service/bean/ThirdPartyGB.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/WvpRedisMsg.java b/src/main/java/com/genersoft/iot/vmp/service/bean/WvpRedisMsg.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/WvpRedisMsgCmd.java b/src/main/java/com/genersoft/iot/vmp/service/bean/WvpRedisMsgCmd.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java old mode 100644 new mode 100755 index b484806c..166b1922 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java @@ -210,7 +210,7 @@ public class DeviceServiceImpl implements IDeviceService { redisCatchStorage.updateDevice(device); deviceMapper.update(device); //进行通道离线 - deviceChannelMapper.offlineByDeviceId(deviceId); +// deviceChannelMapper.offlineByDeviceId(deviceId); // 离线释放所有ssrc List ssrcTransactions = streamSession.getSsrcTransactionForAll(deviceId, null, null, null); if (ssrcTransactions != null && ssrcTransactions.size() > 0) { diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/LogServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/LogServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java old mode 100644 new mode 100755 index 580561b3..f8c1ba18 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java @@ -24,23 +24,30 @@ import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.utils.JsonUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import com.genersoft.iot.vmp.vmanager.bean.RecordFile; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; +import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import java.io.File; import java.time.LocalDateTime; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; /** * 媒体服务器节点管理 @@ -104,6 +111,11 @@ public class MediaServerServiceImpl implements IMediaServerService { @Autowired private RedisTemplate redisTemplate; + @Qualifier("taskExecutor") + @Autowired + private ThreadPoolTaskExecutor taskExecutor; + + /** * 初始化 @@ -149,7 +161,7 @@ public class MediaServerServiceImpl implements IMediaServerService { } if (streamId == null) { - streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); + streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase(); } int ssrcCheckParam = 0; if (ssrcCheck && tcpMode > 1) { @@ -158,7 +170,7 @@ public class MediaServerServiceImpl implements IMediaServerService { } int rtpServerPort; if (mediaServerItem.isRtpEnable()) { - rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0)?Integer.parseInt(ssrc):0, port, reUsePort, tcpMode); + rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0) ? Long.parseLong(ssrc) : 0, port, reUsePort, tcpMode); } else { rtpServerPort = mediaServerItem.getRtpProxyPort(); } @@ -749,4 +761,89 @@ public class MediaServerServiceImpl implements IMediaServerService { return result; } + @Override + public List getRecords(String app, String stream, String startTime, String endTime, List mediaServerItems) { + Assert.notNull(app, "app不存在"); + Assert.notNull(stream, "stream不存在"); + Assert.notNull(startTime, "startTime不存在"); + Assert.notNull(endTime, "endTime不存在"); + Assert.notEmpty(mediaServerItems, "流媒体列表为空"); + + CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()]; + for (int i = 0; i < mediaServerItems.size(); i++) { + completableFutures[i] = getRecordFilesForOne(app, stream, startTime, endTime, mediaServerItems.get(i)); + } + List result = new ArrayList<>(); + for (int i = 0; i < completableFutures.length; i++) { + try { + List list = (List) completableFutures[i].get(); + if (!list.isEmpty()) { + for (int g = 0; g < list.size(); g++) { + list.get(g).setMediaServerId(mediaServerItems.get(i).getId()); + } + result.addAll(list); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } + } + Comparator comparator = Comparator.comparing(RecordFile::getFileName); + result.sort(comparator); + return result; + } + + @Override + public List getRecordDates(String app, String stream, int year, int month, List mediaServerItems) { + Assert.notNull(app, "app不存在"); + Assert.notNull(stream, "stream不存在"); + Assert.notEmpty(mediaServerItems, "流媒体列表为空"); + CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()]; + + for (int i = 0; i < mediaServerItems.size(); i++) { + completableFutures[i] = getRecordDatesForOne(app, stream, year, month, mediaServerItems.get(i)); + } + List result = new ArrayList<>(); + CompletableFuture.allOf(completableFutures).join(); + for (CompletableFuture completableFuture : completableFutures) { + try { + List list = (List) completableFuture.get(); + result.addAll(list); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } + } + Collections.sort(result); + return result; + } + + @Async + public CompletableFuture> getRecordDatesForOne(String app, String stream, int year, int month, MediaServerItem mediaServerItem) { + JSONObject fileListJson = assistRESTfulUtils.getDateList(mediaServerItem, app, stream, year, month); + if (fileListJson != null && !fileListJson.isEmpty()) { + if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) { + JSONArray data = fileListJson.getJSONArray("data"); + return CompletableFuture.completedFuture(data.toJavaList(String.class)); + } + } + return CompletableFuture.completedFuture(new ArrayList<>()); + } + + @Async + public CompletableFuture> getRecordFilesForOne(String app, String stream, String startTime, String endTime, MediaServerItem mediaServerItem) { + JSONObject fileListJson = assistRESTfulUtils.getFileList(mediaServerItem, 1, 100000000, app, stream, startTime, endTime); + if (fileListJson != null && !fileListJson.isEmpty()) { + if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) { + JSONObject data = fileListJson.getJSONObject("data"); + JSONArray list = data.getJSONArray("list"); + if (list != null) { + return CompletableFuture.completedFuture(list.toJavaList(RecordFile.class)); + } + } + } + return CompletableFuture.completedFuture(new ArrayList<>()); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/RoleServerImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/RoleServerImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGpsMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGpsMsgListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamResponseListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamResponseListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusMsgListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisStreamMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisStreamMsgListener.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/ChannelSourceInfo.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/ChannelSourceInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/LogDto.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/LogDto.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/PlatformRegisterInfo.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/PlatformRegisterInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/RecordInfo.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/RecordInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/Role.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/Role.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/User.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/User.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/utils/Coordtransform.java b/src/main/java/com/genersoft/iot/vmp/utils/Coordtransform.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java old mode 100644 new mode 100755 index 23cb9dac..1abf2c6c --- a/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java @@ -1,6 +1,8 @@ package com.genersoft.iot.vmp.utils; +import org.apache.commons.lang3.ObjectUtils; + import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -109,6 +111,9 @@ public class DateUtil { } public static long getDifferenceForNow(String keepaliveTime) { + if (ObjectUtils.isEmpty(keepaliveTime)) { + return 0; + } Instant beforeInstant = Instant.from(formatter.parse(keepaliveTime)); return ChronoUnit.MILLIS.between(beforeInstant, Instant.now()); } diff --git a/src/main/java/com/genersoft/iot/vmp/utils/GitUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/GitUtil.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/utils/GpsUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/GpsUtil.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/utils/JsonUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/JsonUtil.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java b/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java old mode 100644 new mode 100755 index 53238754..18065242 --- a/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java @@ -1,50 +1,50 @@ -package com.genersoft.iot.vmp.utils; - -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.stereotype.Component; - -/** - * @description:spring bean获取工厂,获取spring中的已初始化的bean - * @author: swwheihei - * @date: 2019年6月25日 下午4:51:52 - * - */ -@Component -public class SpringBeanFactory implements ApplicationContextAware { - - // Spring应用上下文环境 - private static ApplicationContext applicationContext; - - /** - * 实现ApplicationContextAware接口的回调方法,设置上下文环境 - */ - @Override - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException { - SpringBeanFactory.applicationContext = applicationContext; - } - - public static ApplicationContext getApplicationContext() { - return applicationContext; - } - - /** - * 获取对象 这里重写了bean方法,起主要作用 - */ - public static T getBean(String beanId) throws BeansException { - if (applicationContext == null) { - return null; - } - return (T) applicationContext.getBean(beanId); - } - - /** - * 获取当前环境 - */ - public static String getActiveProfile() { - return applicationContext.getEnvironment().getActiveProfiles()[0]; - } - -} +package com.genersoft.iot.vmp.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * @description:spring bean获取工厂,获取spring中的已初始化的bean + * @author: swwheihei + * @date: 2019年6月25日 下午4:51:52 + * + */ +@Component +public class SpringBeanFactory implements ApplicationContextAware { + + // Spring应用上下文环境 + private static ApplicationContext applicationContext; + + /** + * 实现ApplicationContextAware接口的回调方法,设置上下文环境 + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + SpringBeanFactory.applicationContext = applicationContext; + } + + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + /** + * 获取对象 这里重写了bean方法,起主要作用 + */ + public static T getBean(String beanId) throws BeansException { + if (applicationContext == null) { + return null; + } + return (T) applicationContext.getBean(beanId); + } + + /** + * 获取当前环境 + */ + public static String getActiveProfile() { + return applicationContext.getEnvironment().getActiveProfiles()[0]; + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/utils/SystemInfoUtils.java b/src/main/java/com/genersoft/iot/vmp/utils/SystemInfoUtils.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/utils/UJson.java b/src/main/java/com/genersoft/iot/vmp/utils/UJson.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java b/src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java old mode 100644 new mode 100755 index 466a5035..86b7dce1 --- a/src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java @@ -1,45 +1,45 @@ -package com.genersoft.iot.vmp.utils.redis; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONReader; -import com.alibaba.fastjson2.JSONWriter; -import org.springframework.data.redis.serializer.RedisSerializer; -import org.springframework.data.redis.serializer.SerializationException; - -import java.nio.charset.Charset; - -/** - * @description:使用fastjson实现redis的序列化 - * @author: swwheihei - * @date: 2020年5月6日 下午8:40:11 - */ -public class FastJsonRedisSerializer implements RedisSerializer { - - public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); - - private Class clazz; - - public FastJsonRedisSerializer(Class clazz) { - super(); - this.clazz = clazz; - } - - @Override - public byte[] serialize(T t) throws SerializationException { - if (t == null) { - return new byte[0]; - } - return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName, JSONWriter.Feature.WritePairAsJavaBean).getBytes(DEFAULT_CHARSET); - } - - @Override - public T deserialize(byte[] bytes) throws SerializationException { - if (bytes == null || bytes.length <= 0) { - return null; - } - String str = new String(bytes, DEFAULT_CHARSET); - return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType); - } - - -} +package com.genersoft.iot.vmp.utils.redis; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONReader; +import com.alibaba.fastjson2.JSONWriter; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; + +import java.nio.charset.Charset; + +/** + * @description:使用fastjson实现redis的序列化 + * @author: swwheihei + * @date: 2020年5月6日 下午8:40:11 + */ +public class FastJsonRedisSerializer implements RedisSerializer { + + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + private Class clazz; + + public FastJsonRedisSerializer(Class clazz) { + super(); + this.clazz = clazz; + } + + @Override + public byte[] serialize(T t) throws SerializationException { + if (t == null) { + return new byte[0]; + } + return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName, JSONWriter.Feature.WritePairAsJavaBean).getBytes(DEFAULT_CHARSET); + } + + @Override + public T deserialize(byte[] bytes) throws SerializationException { + if (bytes == null || bytes.length <= 0) { + return null; + } + String str = new String(bytes, DEFAULT_CHARSET); + return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType); + } + + +} diff --git a/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java old mode 100644 new mode 100755 index 48369d42..101a3b30 --- a/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java @@ -1,47 +1,47 @@ -package com.genersoft.iot.vmp.utils.redis; - -import com.google.common.collect.Lists; -import org.springframework.data.redis.core.Cursor; -import org.springframework.data.redis.core.RedisCallback; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.ScanOptions; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * Redis工具类 - * - * @author swwheihei - * @date 2020年5月6日 下午8:27:29 - */ -@SuppressWarnings(value = {"rawtypes", "unchecked"}) -public class RedisUtil { - - /** - * 模糊查询 - * - * @param query 查询参数 - * @return - */ - public static List scan(RedisTemplate redisTemplate, String query) { - - Set resultKeys = (Set) redisTemplate.execute((RedisCallback>) connection -> { - ScanOptions scanOptions = ScanOptions.scanOptions().match("*" + query + "*").count(1000).build(); - Cursor scan = connection.scan(scanOptions); - Set keys = new HashSet<>(); - while (scan.hasNext()) { - byte[] next = scan.next(); - keys.add(new String(next)); - } - return keys; - }); - - return Lists.newArrayList(resultKeys); - } -} - - - +package com.genersoft.iot.vmp.utils.redis; + +import com.google.common.collect.Lists; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ScanOptions; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Redis工具类 + * + * @author swwheihei + * @date 2020年5月6日 下午8:27:29 + */ +@SuppressWarnings(value = {"rawtypes", "unchecked"}) +public class RedisUtil { + + /** + * 模糊查询 + * + * @param query 查询参数 + * @return + */ + public static List scan(RedisTemplate redisTemplate, String query) { + + Set resultKeys = (Set) redisTemplate.execute((RedisCallback>) connection -> { + ScanOptions scanOptions = ScanOptions.scanOptions().match("*" + query + "*").count(1000).build(); + Cursor scan = connection.scan(scanOptions); + Set keys = new HashSet<>(); + while (scan.hasNext()) { + byte[] next = scan.next(); + keys.add(new String(next)); + } + return keys; + }); + + return Lists.newArrayList(resultKeys); + } +} + + + diff --git a/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil2.java b/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil2.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/BaseTree.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/BaseTree.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/BatchGBStreamParam.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/BatchGBStreamParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultEx.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultEx.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultFilter.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultFilter.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/OtherPsSendInfo.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/OtherPsSendInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/OtherRtpSendInfo.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/OtherRtpSendInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/PlayTypeEnum.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/PlayTypeEnum.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceBaseInfo.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceBaseInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceInfo.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/SnapPath.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/SnapPath.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamPushExcelDto.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamPushExcelDto.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/SystemConfigInfo.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/SystemConfigInfo.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/SseController/SseController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/SseController/SseController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/bean/PlayResult.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/bean/PlayResult.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java old mode 100644 new mode 100755 index 81ccb573..491e079d --- a/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java @@ -91,10 +91,10 @@ public class PsController { if (isSend != null && isSend && callId == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(),"isSend为true时,CallID不能为空"); } - int ssrcInt = 0; + long ssrcInt = 0; if (ssrc != null) { try { - ssrcInt = Integer.parseInt(ssrc); + ssrcInt = Long.parseLong(ssrc); }catch (NumberFormatException e) { throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误"); } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java old mode 100644 new mode 100755 index 638ed3ff..bf83c944 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java @@ -91,10 +91,10 @@ public class RtpController { if (isSend != null && isSend && callId == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(),"isSend为true时,CallID不能为空"); } - int ssrcInt = 0; + long ssrcInt = 0; if (ssrc != null) { try { - ssrcInt = Integer.parseInt(ssrc); + ssrcInt = Long.parseLong(ssrc); }catch (NumberFormatException e) { throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误"); } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/user/RoleController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/user/RoleController.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java old mode 100644 new mode 100755 diff --git a/web_src/src/App.vue b/web_src/src/App.vue old mode 100644 new mode 100755 diff --git a/web_src/src/assets/icons.png b/web_src/src/assets/icons.png old mode 100644 new mode 100755 diff --git a/web_src/src/assets/loading.png b/web_src/src/assets/loading.png old mode 100644 new mode 100755 diff --git a/web_src/src/assets/login-bg.jpg b/web_src/src/assets/login-bg.jpg old mode 100644 new mode 100755 diff --git a/web_src/src/assets/login-cloud.png b/web_src/src/assets/login-cloud.png old mode 100644 new mode 100755 diff --git a/web_src/src/assets/logo.png b/web_src/src/assets/logo.png old mode 100644 new mode 100755 diff --git a/web_src/src/assets/play.png b/web_src/src/assets/play.png old mode 100644 new mode 100755 diff --git a/web_src/src/assets/zlm-log.png b/web_src/src/assets/zlm-log.png old mode 100644 new mode 100755 diff --git a/web_src/src/components/CloudRecord.vue b/web_src/src/components/CloudRecord.vue old mode 100644 new mode 100755 index b046fc91..c13cdc4a --- a/web_src/src/components/CloudRecord.vue +++ b/web_src/src/components/CloudRecord.vue @@ -47,19 +47,17 @@ :total="total"> -