Commit d0ef68af3fad9592c7bd9e61ed97244cd4a93e59
Committed by
GitHub
Merge branch '648540858:wvp-28181-2.0' into wvp-28181-2.0
Showing
359 changed files
with
5728 additions
and
5183 deletions
doc/_content/introduction/config.md
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
| 1 | -package com.genersoft.iot.vmp; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.utils.GitUtil; | |
| 4 | -import com.genersoft.iot.vmp.utils.SpringBeanFactory; | |
| 5 | -import org.slf4j.Logger; | |
| 6 | -import org.slf4j.LoggerFactory; | |
| 7 | -import org.springframework.boot.SpringApplication; | |
| 8 | -import org.springframework.boot.autoconfigure.SpringBootApplication; | |
| 9 | -import org.springframework.boot.builder.SpringApplicationBuilder; | |
| 10 | -import org.springframework.boot.web.servlet.ServletComponentScan; | |
| 11 | -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; | |
| 12 | -import org.springframework.context.ConfigurableApplicationContext; | |
| 13 | -import org.springframework.scheduling.annotation.EnableScheduling; | |
| 14 | - | |
| 15 | -import javax.servlet.ServletContext; | |
| 16 | -import javax.servlet.ServletException; | |
| 17 | -import javax.servlet.SessionCookieConfig; | |
| 18 | -import javax.servlet.SessionTrackingMode; | |
| 19 | -import java.util.Collections; | |
| 20 | - | |
| 21 | -/** | |
| 22 | - * 启动类 | |
| 23 | - */ | |
| 24 | -@ServletComponentScan("com.genersoft.iot.vmp.conf") | |
| 25 | -@SpringBootApplication | |
| 26 | -@EnableScheduling | |
| 27 | -public class VManageBootstrap extends SpringBootServletInitializer { | |
| 28 | - | |
| 29 | - private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class); | |
| 30 | - | |
| 31 | - private static String[] args; | |
| 32 | - private static ConfigurableApplicationContext context; | |
| 33 | - public static void main(String[] args) { | |
| 34 | - VManageBootstrap.args = args; | |
| 35 | - VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); | |
| 36 | - GitUtil gitUtil1 = SpringBeanFactory.getBean("gitUtil"); | |
| 37 | - logger.info("构建版本: {}", gitUtil1.getBuildVersion()); | |
| 38 | - logger.info("构建时间: {}", gitUtil1.getBuildDate()); | |
| 39 | - logger.info("GIT最后提交时间: {}", gitUtil1.getCommitTime()); | |
| 40 | - } | |
| 41 | - // 项目重启 | |
| 42 | - public static void restart() { | |
| 43 | - context.close(); | |
| 44 | - VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); | |
| 45 | - } | |
| 46 | - | |
| 47 | - @Override | |
| 48 | - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { | |
| 49 | - return application.sources(VManageBootstrap.class); | |
| 50 | - } | |
| 51 | - | |
| 52 | - @Override | |
| 53 | - public void onStartup(ServletContext servletContext) throws ServletException { | |
| 54 | - super.onStartup(servletContext); | |
| 55 | - | |
| 56 | - servletContext.setSessionTrackingModes( | |
| 57 | - Collections.singleton(SessionTrackingMode.COOKIE) | |
| 58 | - ); | |
| 59 | - SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig(); | |
| 60 | - sessionCookieConfig.setHttpOnly(true); | |
| 61 | - | |
| 62 | - } | |
| 63 | -} | |
| 1 | +package com.genersoft.iot.vmp; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.utils.GitUtil; | |
| 4 | +import com.genersoft.iot.vmp.utils.SpringBeanFactory; | |
| 5 | +import org.slf4j.Logger; | |
| 6 | +import org.slf4j.LoggerFactory; | |
| 7 | +import org.springframework.boot.SpringApplication; | |
| 8 | +import org.springframework.boot.autoconfigure.SpringBootApplication; | |
| 9 | +import org.springframework.boot.builder.SpringApplicationBuilder; | |
| 10 | +import org.springframework.boot.web.servlet.ServletComponentScan; | |
| 11 | +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; | |
| 12 | +import org.springframework.context.ConfigurableApplicationContext; | |
| 13 | +import org.springframework.scheduling.annotation.EnableScheduling; | |
| 14 | + | |
| 15 | +import javax.servlet.ServletContext; | |
| 16 | +import javax.servlet.ServletException; | |
| 17 | +import javax.servlet.SessionCookieConfig; | |
| 18 | +import javax.servlet.SessionTrackingMode; | |
| 19 | +import java.util.Collections; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * 启动类 | |
| 23 | + */ | |
| 24 | +@ServletComponentScan("com.genersoft.iot.vmp.conf") | |
| 25 | +@SpringBootApplication | |
| 26 | +@EnableScheduling | |
| 27 | +public class VManageBootstrap extends SpringBootServletInitializer { | |
| 28 | + | |
| 29 | + private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class); | |
| 30 | + | |
| 31 | + private static String[] args; | |
| 32 | + private static ConfigurableApplicationContext context; | |
| 33 | + public static void main(String[] args) { | |
| 34 | + VManageBootstrap.args = args; | |
| 35 | + VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); | |
| 36 | + GitUtil gitUtil1 = SpringBeanFactory.getBean("gitUtil"); | |
| 37 | + logger.info("构建版本: {}", gitUtil1.getBuildVersion()); | |
| 38 | + logger.info("构建时间: {}", gitUtil1.getBuildDate()); | |
| 39 | + logger.info("GIT最后提交时间: {}", gitUtil1.getCommitTime()); | |
| 40 | + } | |
| 41 | + // 项目重启 | |
| 42 | + public static void restart() { | |
| 43 | + context.close(); | |
| 44 | + VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); | |
| 45 | + } | |
| 46 | + | |
| 47 | + @Override | |
| 48 | + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { | |
| 49 | + return application.sources(VManageBootstrap.class); | |
| 50 | + } | |
| 51 | + | |
| 52 | + @Override | |
| 53 | + public void onStartup(ServletContext servletContext) throws ServletException { | |
| 54 | + super.onStartup(servletContext); | |
| 55 | + | |
| 56 | + servletContext.setSessionTrackingModes( | |
| 57 | + Collections.singleton(SessionTrackingMode.COOKIE) | |
| 58 | + ); | |
| 59 | + SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig(); | |
| 60 | + sessionCookieConfig.setHttpOnly(true); | |
| 61 | + | |
| 62 | + } | |
| 63 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| 1 | -package com.genersoft.iot.vmp.common; | |
| 2 | - | |
| 3 | -/** | |
| 4 | - * @description: 定义常量 | |
| 5 | - * @author: swwheihei | |
| 6 | - * @date: 2019年5月30日 下午3:04:04 | |
| 7 | - * | |
| 8 | - */ | |
| 9 | -public class VideoManagerConstants { | |
| 10 | - | |
| 11 | - public static final String WVP_SERVER_PREFIX = "VMP_SIGNALLING_SERVER_INFO_"; | |
| 12 | - | |
| 13 | - public static final String WVP_SERVER_STREAM_PREFIX = "VMP_SIGNALLING_STREAM_"; | |
| 14 | - | |
| 15 | - public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_"; | |
| 16 | - | |
| 17 | - public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_"; | |
| 18 | - | |
| 19 | - public static final String DEVICE_PREFIX = "VMP_DEVICE_"; | |
| 20 | - | |
| 21 | - // 设备同步完成 | |
| 22 | - public static final String DEVICE_SYNC_PREFIX = "VMP_DEVICE_SYNC_"; | |
| 23 | - | |
| 24 | - public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_"; | |
| 25 | - | |
| 26 | - public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_"; | |
| 27 | - | |
| 28 | - // TODO 此处多了一个_,暂不修改 | |
| 29 | - public static final String INVITE_PREFIX = "VMP_INVITE"; | |
| 30 | - public static final String PLAYER_PREFIX = "VMP_INVITE_PLAY_"; | |
| 31 | - public static final String PLAY_BLACK_PREFIX = "VMP_INVITE_PLAYBACK_"; | |
| 32 | - public static final String DOWNLOAD_PREFIX = "VMP_INVITE_DOWNLOAD_"; | |
| 33 | - | |
| 34 | - public static final String PLATFORM_KEEPALIVE_PREFIX = "VMP_PLATFORM_KEEPALIVE_"; | |
| 35 | - | |
| 36 | - public static final String PLATFORM_CATCH_PREFIX = "VMP_PLATFORM_CATCH_"; | |
| 37 | - | |
| 38 | - public static final String PLATFORM_REGISTER_PREFIX = "VMP_PLATFORM_REGISTER_"; | |
| 39 | - | |
| 40 | - public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_"; | |
| 41 | - | |
| 42 | - public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_PLATFORM_SEND_RTP_INFO_"; | |
| 43 | - | |
| 44 | - public static final String EVENT_ONLINE_REGISTER = "1"; | |
| 45 | - | |
| 46 | - public static final String EVENT_ONLINE_MESSAGE = "3"; | |
| 47 | - | |
| 48 | - public static final String EVENT_OUTLINE_UNREGISTER = "1"; | |
| 49 | - | |
| 50 | - public static final String EVENT_OUTLINE_TIMEOUT = "2"; | |
| 51 | - | |
| 52 | - public static final String MEDIA_SSRC_USED_PREFIX = "VMP_MEDIA_USED_SSRC_"; | |
| 53 | - | |
| 54 | - public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_"; | |
| 55 | - | |
| 56 | - public static final String MEDIA_STREAM_AUTHORITY = "MEDIA_STREAM_AUTHORITY_"; | |
| 57 | - | |
| 58 | - public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_"; | |
| 59 | - | |
| 60 | - public static final String SIP_SN_PREFIX = "VMP_SIP_SN_"; | |
| 61 | - | |
| 62 | - public static final String SIP_SUBSCRIBE_PREFIX = "VMP_SIP_SUBSCRIBE_"; | |
| 63 | - | |
| 64 | - public static final String SYSTEM_INFO_CPU_PREFIX = "VMP_SYSTEM_INFO_CPU_"; | |
| 65 | - | |
| 66 | - public static final String SYSTEM_INFO_MEM_PREFIX = "VMP_SYSTEM_INFO_MEM_"; | |
| 67 | - | |
| 68 | - public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_"; | |
| 69 | - | |
| 70 | - public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_"; | |
| 71 | - | |
| 72 | - public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_"; | |
| 73 | - | |
| 74 | - | |
| 75 | - | |
| 76 | - | |
| 77 | - //************************** redis 消息********************************* | |
| 78 | - | |
| 79 | - /** | |
| 80 | - * 流变化的通知 | |
| 81 | - */ | |
| 82 | - public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_"; | |
| 83 | - | |
| 84 | - /** | |
| 85 | - * 接收推流设备的GPS变化通知 | |
| 86 | - */ | |
| 87 | - public static final String VM_MSG_GPS = "VM_MSG_GPS"; | |
| 88 | - | |
| 89 | - /** | |
| 90 | - * 接收推流设备的GPS变化通知 | |
| 91 | - */ | |
| 92 | - public static final String VM_MSG_PUSH_STREAM_STATUS_CHANGE = "VM_MSG_PUSH_STREAM_STATUS_CHANGE"; | |
| 93 | - /** | |
| 94 | - * 接收推流设备列表更新变化通知 | |
| 95 | - */ | |
| 96 | - public static final String VM_MSG_PUSH_STREAM_LIST_CHANGE = "VM_MSG_PUSH_STREAM_LIST_CHANGE"; | |
| 97 | - | |
| 98 | - /** | |
| 99 | - * redis 消息通知设备推流到平台 | |
| 100 | - */ | |
| 101 | - public static final String VM_MSG_STREAM_PUSH_REQUESTED = "VM_MSG_STREAM_PUSH_REQUESTED"; | |
| 102 | - | |
| 103 | - /** | |
| 104 | - * redis 消息通知上级平台开始观看流 | |
| 105 | - */ | |
| 106 | - public static final String VM_MSG_STREAM_START_PLAY_NOTIFY = "VM_MSG_STREAM_START_PLAY_NOTIFY"; | |
| 107 | - | |
| 108 | - /** | |
| 109 | - * redis 消息通知上级平台停止观看流 | |
| 110 | - */ | |
| 111 | - public static final String VM_MSG_STREAM_STOP_PLAY_NOTIFY = "VM_MSG_STREAM_STOP_PLAY_NOTIFY"; | |
| 112 | - | |
| 113 | - /** | |
| 114 | - * redis 消息接收关闭一个推流 | |
| 115 | - */ | |
| 116 | - public static final String VM_MSG_STREAM_PUSH_CLOSE_REQUESTED = "VM_MSG_STREAM_PUSH_CLOSE_REQUESTED"; | |
| 117 | - | |
| 118 | - | |
| 119 | - /** | |
| 120 | - * redis 消息通知平台通知设备推流结果 | |
| 121 | - */ | |
| 122 | - public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE"; | |
| 123 | - | |
| 124 | - /** | |
| 125 | - * redis 通知平台关闭推流 | |
| 126 | - */ | |
| 127 | - public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE"; | |
| 128 | - | |
| 129 | - /** | |
| 130 | - * redis 消息请求所有的在线通道 | |
| 131 | - */ | |
| 132 | - public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED"; | |
| 133 | - | |
| 134 | - /** | |
| 135 | - * 移动位置订阅通知 | |
| 136 | - */ | |
| 137 | - public static final String VM_MSG_SUBSCRIBE_MOBILE_POSITION = "mobileposition"; | |
| 138 | - | |
| 139 | - /** | |
| 140 | - * 报警订阅的通知(收到报警向redis发出通知) | |
| 141 | - */ | |
| 142 | - public static final String VM_MSG_SUBSCRIBE_ALARM = "alarm"; | |
| 143 | - | |
| 144 | - | |
| 145 | - /** | |
| 146 | - * 报警通知的发送 (收到redis发出的通知,转发给其他平台) | |
| 147 | - */ | |
| 148 | - public static final String VM_MSG_SUBSCRIBE_ALARM_RECEIVE= "alarm_receive"; | |
| 149 | - | |
| 150 | - /** | |
| 151 | - * 设备状态订阅的通知 | |
| 152 | - */ | |
| 153 | - public static final String VM_MSG_SUBSCRIBE_DEVICE_STATUS = "device"; | |
| 154 | - | |
| 155 | - | |
| 156 | - //************************** 第三方 **************************************** | |
| 157 | - | |
| 158 | - public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; | |
| 159 | - public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; | |
| 160 | - public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_"; | |
| 161 | - public static final String WVP_OTHER_SEND_PS_INFO = "VMP_OTHER_SEND_PS_INFO_"; | |
| 162 | - public static final String WVP_OTHER_RECEIVE_RTP_INFO = "VMP_OTHER_RECEIVE_RTP_INFO_"; | |
| 163 | - public static final String WVP_OTHER_RECEIVE_PS_INFO = "VMP_OTHER_RECEIVE_PS_INFO_"; | |
| 164 | - | |
| 165 | - /** | |
| 166 | - * Redis Const | |
| 167 | - * 设备录像信息结果前缀 | |
| 168 | - */ | |
| 169 | - public static final String REDIS_RECORD_INFO_RES_PRE = "GB_RECORD_INFO_RES_"; | |
| 170 | - /** | |
| 171 | - * Redis Const | |
| 172 | - * 设备录像信息结果前缀 | |
| 173 | - */ | |
| 174 | - public static final String REDIS_RECORD_INFO_RES_COUNT_PRE = "GB_RECORD_INFO_RES_COUNT:"; | |
| 175 | - | |
| 176 | -} | |
| 1 | +package com.genersoft.iot.vmp.common; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * @description: 定义常量 | |
| 5 | + * @author: swwheihei | |
| 6 | + * @date: 2019年5月30日 下午3:04:04 | |
| 7 | + * | |
| 8 | + */ | |
| 9 | +public class VideoManagerConstants { | |
| 10 | + | |
| 11 | + public static final String WVP_SERVER_PREFIX = "VMP_SIGNALLING_SERVER_INFO_"; | |
| 12 | + | |
| 13 | + public static final String WVP_SERVER_STREAM_PREFIX = "VMP_SIGNALLING_STREAM_"; | |
| 14 | + | |
| 15 | + public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_"; | |
| 16 | + | |
| 17 | + public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_"; | |
| 18 | + | |
| 19 | + public static final String DEVICE_PREFIX = "VMP_DEVICE_"; | |
| 20 | + | |
| 21 | + // 设备同步完成 | |
| 22 | + public static final String DEVICE_SYNC_PREFIX = "VMP_DEVICE_SYNC_"; | |
| 23 | + | |
| 24 | + public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_"; | |
| 25 | + | |
| 26 | + public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_"; | |
| 27 | + | |
| 28 | + // TODO 此处多了一个_,暂不修改 | |
| 29 | + public static final String INVITE_PREFIX = "VMP_INVITE"; | |
| 30 | + public static final String PLAYER_PREFIX = "VMP_INVITE_PLAY_"; | |
| 31 | + public static final String PLAY_BLACK_PREFIX = "VMP_INVITE_PLAYBACK_"; | |
| 32 | + public static final String DOWNLOAD_PREFIX = "VMP_INVITE_DOWNLOAD_"; | |
| 33 | + | |
| 34 | + public static final String PLATFORM_KEEPALIVE_PREFIX = "VMP_PLATFORM_KEEPALIVE_"; | |
| 35 | + | |
| 36 | + public static final String PLATFORM_CATCH_PREFIX = "VMP_PLATFORM_CATCH_"; | |
| 37 | + | |
| 38 | + public static final String PLATFORM_REGISTER_PREFIX = "VMP_PLATFORM_REGISTER_"; | |
| 39 | + | |
| 40 | + public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_"; | |
| 41 | + | |
| 42 | + public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_PLATFORM_SEND_RTP_INFO_"; | |
| 43 | + | |
| 44 | + public static final String EVENT_ONLINE_REGISTER = "1"; | |
| 45 | + | |
| 46 | + public static final String EVENT_ONLINE_MESSAGE = "3"; | |
| 47 | + | |
| 48 | + public static final String EVENT_OUTLINE_UNREGISTER = "1"; | |
| 49 | + | |
| 50 | + public static final String EVENT_OUTLINE_TIMEOUT = "2"; | |
| 51 | + | |
| 52 | + public static final String MEDIA_SSRC_USED_PREFIX = "VMP_MEDIA_USED_SSRC_"; | |
| 53 | + | |
| 54 | + public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_"; | |
| 55 | + | |
| 56 | + public static final String MEDIA_STREAM_AUTHORITY = "MEDIA_STREAM_AUTHORITY_"; | |
| 57 | + | |
| 58 | + public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_"; | |
| 59 | + | |
| 60 | + public static final String SIP_SN_PREFIX = "VMP_SIP_SN_"; | |
| 61 | + | |
| 62 | + public static final String SIP_SUBSCRIBE_PREFIX = "VMP_SIP_SUBSCRIBE_"; | |
| 63 | + | |
| 64 | + public static final String SYSTEM_INFO_CPU_PREFIX = "VMP_SYSTEM_INFO_CPU_"; | |
| 65 | + | |
| 66 | + public static final String SYSTEM_INFO_MEM_PREFIX = "VMP_SYSTEM_INFO_MEM_"; | |
| 67 | + | |
| 68 | + public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_"; | |
| 69 | + | |
| 70 | + public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_"; | |
| 71 | + | |
| 72 | + public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_"; | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + //************************** redis 消息********************************* | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * 流变化的通知 | |
| 81 | + */ | |
| 82 | + public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_"; | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * 接收推流设备的GPS变化通知 | |
| 86 | + */ | |
| 87 | + public static final String VM_MSG_GPS = "VM_MSG_GPS"; | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * 接收推流设备的GPS变化通知 | |
| 91 | + */ | |
| 92 | + public static final String VM_MSG_PUSH_STREAM_STATUS_CHANGE = "VM_MSG_PUSH_STREAM_STATUS_CHANGE"; | |
| 93 | + /** | |
| 94 | + * 接收推流设备列表更新变化通知 | |
| 95 | + */ | |
| 96 | + public static final String VM_MSG_PUSH_STREAM_LIST_CHANGE = "VM_MSG_PUSH_STREAM_LIST_CHANGE"; | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * redis 消息通知设备推流到平台 | |
| 100 | + */ | |
| 101 | + public static final String VM_MSG_STREAM_PUSH_REQUESTED = "VM_MSG_STREAM_PUSH_REQUESTED"; | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * redis 消息通知上级平台开始观看流 | |
| 105 | + */ | |
| 106 | + public static final String VM_MSG_STREAM_START_PLAY_NOTIFY = "VM_MSG_STREAM_START_PLAY_NOTIFY"; | |
| 107 | + | |
| 108 | + /** | |
| 109 | + * redis 消息通知上级平台停止观看流 | |
| 110 | + */ | |
| 111 | + public static final String VM_MSG_STREAM_STOP_PLAY_NOTIFY = "VM_MSG_STREAM_STOP_PLAY_NOTIFY"; | |
| 112 | + | |
| 113 | + /** | |
| 114 | + * redis 消息接收关闭一个推流 | |
| 115 | + */ | |
| 116 | + public static final String VM_MSG_STREAM_PUSH_CLOSE_REQUESTED = "VM_MSG_STREAM_PUSH_CLOSE_REQUESTED"; | |
| 117 | + | |
| 118 | + | |
| 119 | + /** | |
| 120 | + * redis 消息通知平台通知设备推流结果 | |
| 121 | + */ | |
| 122 | + public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE"; | |
| 123 | + | |
| 124 | + /** | |
| 125 | + * redis 通知平台关闭推流 | |
| 126 | + */ | |
| 127 | + public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE"; | |
| 128 | + | |
| 129 | + /** | |
| 130 | + * redis 消息请求所有的在线通道 | |
| 131 | + */ | |
| 132 | + public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED"; | |
| 133 | + | |
| 134 | + /** | |
| 135 | + * 移动位置订阅通知 | |
| 136 | + */ | |
| 137 | + public static final String VM_MSG_SUBSCRIBE_MOBILE_POSITION = "mobileposition"; | |
| 138 | + | |
| 139 | + /** | |
| 140 | + * 报警订阅的通知(收到报警向redis发出通知) | |
| 141 | + */ | |
| 142 | + public static final String VM_MSG_SUBSCRIBE_ALARM = "alarm"; | |
| 143 | + | |
| 144 | + | |
| 145 | + /** | |
| 146 | + * 报警通知的发送 (收到redis发出的通知,转发给其他平台) | |
| 147 | + */ | |
| 148 | + public static final String VM_MSG_SUBSCRIBE_ALARM_RECEIVE= "alarm_receive"; | |
| 149 | + | |
| 150 | + /** | |
| 151 | + * 设备状态订阅的通知 | |
| 152 | + */ | |
| 153 | + public static final String VM_MSG_SUBSCRIBE_DEVICE_STATUS = "device"; | |
| 154 | + | |
| 155 | + | |
| 156 | + //************************** 第三方 **************************************** | |
| 157 | + | |
| 158 | + public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; | |
| 159 | + public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; | |
| 160 | + public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_"; | |
| 161 | + public static final String WVP_OTHER_SEND_PS_INFO = "VMP_OTHER_SEND_PS_INFO_"; | |
| 162 | + public static final String WVP_OTHER_RECEIVE_RTP_INFO = "VMP_OTHER_RECEIVE_RTP_INFO_"; | |
| 163 | + public static final String WVP_OTHER_RECEIVE_PS_INFO = "VMP_OTHER_RECEIVE_PS_INFO_"; | |
| 164 | + | |
| 165 | + /** | |
| 166 | + * Redis Const | |
| 167 | + * 设备录像信息结果前缀 | |
| 168 | + */ | |
| 169 | + public static final String REDIS_RECORD_INFO_RES_PRE = "GB_RECORD_INFO_RES_"; | |
| 170 | + /** | |
| 171 | + * Redis Const | |
| 172 | + * 设备录像信息结果前缀 | |
| 173 | + */ | |
| 174 | + public static final String REDIS_RECORD_INFO_RES_COUNT_PRE = "GB_RECORD_INFO_RES_COUNT:"; | |
| 175 | + | |
| 176 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
| ... | ... | @@ -51,7 +51,7 @@ public class ApiAccessFilter extends OncePerRequestFilter { |
| 51 | 51 | |
| 52 | 52 | filterChain.doFilter(servletRequest, servletResponse); |
| 53 | 53 | |
| 54 | - if (uriName != null && userSetting != null && userSetting.getLogInDatebase() != null && userSetting.getLogInDatebase()) { | |
| 54 | + if (uriName != null && userSetting != null && userSetting.getLogInDatabase() != null && userSetting.getLogInDatabase()) { | |
| 55 | 55 | |
| 56 | 56 | LogDto logDto = new LogDto(); |
| 57 | 57 | logDto.setName(uriName); | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
| ... | ... | @@ -4,13 +4,19 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 4 | 4 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| 6 | 6 | import com.genersoft.iot.vmp.service.IPlatformService; |
| 7 | +import com.genersoft.iot.vmp.service.impl.PlatformServiceImpl; | |
| 7 | 8 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 8 | 9 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 10 | +import org.slf4j.Logger; | |
| 11 | +import org.slf4j.LoggerFactory; | |
| 9 | 12 | import org.springframework.beans.factory.annotation.Autowired; |
| 10 | 13 | import org.springframework.boot.CommandLineRunner; |
| 11 | 14 | import org.springframework.core.annotation.Order; |
| 12 | 15 | import org.springframework.stereotype.Component; |
| 13 | 16 | |
| 17 | +import javax.sip.InvalidArgumentException; | |
| 18 | +import javax.sip.SipException; | |
| 19 | +import java.text.ParseException; | |
| 14 | 20 | import java.util.List; |
| 15 | 21 | |
| 16 | 22 | /** |
| ... | ... | @@ -33,6 +39,7 @@ public class SipPlatformRunner implements CommandLineRunner { |
| 33 | 39 | @Autowired |
| 34 | 40 | private ISIPCommanderForPlatform sipCommanderForPlatform; |
| 35 | 41 | |
| 42 | + private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class); | |
| 36 | 43 | |
| 37 | 44 | @Override |
| 38 | 45 | public void run(String... args) throws Exception { |
| ... | ... | @@ -50,9 +57,13 @@ public class SipPlatformRunner implements CommandLineRunner { |
| 50 | 57 | redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); |
| 51 | 58 | if (parentPlatformCatchOld != null) { |
| 52 | 59 | // 取消订阅 |
| 53 | - sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{ | |
| 54 | - platformService.login(parentPlatform); | |
| 55 | - }); | |
| 60 | + try { | |
| 61 | + sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{ | |
| 62 | + platformService.login(parentPlatform); | |
| 63 | + }); | |
| 64 | + } catch (InvalidArgumentException | ParseException | SipException e) { | |
| 65 | + logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage()); | |
| 66 | + } | |
| 56 | 67 | } |
| 57 | 68 | |
| 58 | 69 | // 设置所有平台离线 | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
| ... | ... | @@ -31,7 +31,7 @@ public class UserSetting { |
| 31 | 31 | |
| 32 | 32 | private Boolean recordSip = Boolean.TRUE; |
| 33 | 33 | |
| 34 | - private Boolean logInDatebase = Boolean.TRUE; | |
| 34 | + private Boolean logInDatabase = Boolean.TRUE; | |
| 35 | 35 | |
| 36 | 36 | private Boolean usePushingAsStatus = Boolean.TRUE; |
| 37 | 37 | |
| ... | ... | @@ -132,12 +132,12 @@ public class UserSetting { |
| 132 | 132 | this.interfaceAuthenticationExcludes = interfaceAuthenticationExcludes; |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | - public Boolean getLogInDatebase() { | |
| 136 | - return logInDatebase; | |
| 135 | + public Boolean getLogInDatabase() { | |
| 136 | + return logInDatabase; | |
| 137 | 137 | } |
| 138 | 138 | |
| 139 | - public void setLogInDatebase(Boolean logInDatebase) { | |
| 140 | - this.logInDatebase = logInDatebase; | |
| 139 | + public void setLogInDatabase(Boolean logInDatabase) { | |
| 140 | + this.logInDatabase = logInDatabase; | |
| 141 | 141 | } |
| 142 | 142 | |
| 143 | 143 | public String getServerId() { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
| 1 | -package com.genersoft.iot.vmp.gb28181; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.conf.SipConfig; | |
| 4 | -import com.genersoft.iot.vmp.conf.UserSetting; | |
| 5 | -import com.genersoft.iot.vmp.gb28181.bean.GbStringMsgParserFactory; | |
| 6 | -import com.genersoft.iot.vmp.gb28181.conf.DefaultProperties; | |
| 7 | -import com.genersoft.iot.vmp.gb28181.transmit.ISIPProcessorObserver; | |
| 8 | -import gov.nist.javax.sip.SipProviderImpl; | |
| 9 | -import gov.nist.javax.sip.SipStackImpl; | |
| 10 | -import org.slf4j.Logger; | |
| 11 | -import org.slf4j.LoggerFactory; | |
| 12 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 13 | -import org.springframework.boot.CommandLineRunner; | |
| 14 | -import org.springframework.core.annotation.Order; | |
| 15 | -import org.springframework.stereotype.Component; | |
| 16 | -import org.springframework.util.ObjectUtils; | |
| 17 | - | |
| 18 | -import javax.sip.*; | |
| 19 | -import java.util.*; | |
| 20 | -import java.util.concurrent.ConcurrentHashMap; | |
| 21 | - | |
| 22 | -@Component | |
| 23 | -@Order(value=10) | |
| 24 | -public class SipLayer implements CommandLineRunner { | |
| 25 | - | |
| 26 | - private final static Logger logger = LoggerFactory.getLogger(SipLayer.class); | |
| 27 | - | |
| 28 | - @Autowired | |
| 29 | - private SipConfig sipConfig; | |
| 30 | - | |
| 31 | - @Autowired | |
| 32 | - private ISIPProcessorObserver sipProcessorObserver; | |
| 33 | - | |
| 34 | - @Autowired | |
| 35 | - private UserSetting userSetting; | |
| 36 | - | |
| 37 | - private final Map<String, SipProviderImpl> tcpSipProviderMap = new ConcurrentHashMap<>(); | |
| 38 | - private final Map<String, SipProviderImpl> udpSipProviderMap = new ConcurrentHashMap<>(); | |
| 39 | - | |
| 40 | - @Override | |
| 41 | - public void run(String... args) { | |
| 42 | - List<String> monitorIps = new ArrayList<>(); | |
| 43 | - // 使用逗号分割多个ip | |
| 44 | - String separator = ","; | |
| 45 | - if (sipConfig.getIp().indexOf(separator) > 0) { | |
| 46 | - String[] split = sipConfig.getIp().split(separator); | |
| 47 | - monitorIps.addAll(Arrays.asList(split)); | |
| 48 | - }else { | |
| 49 | - monitorIps.add(sipConfig.getIp()); | |
| 50 | - } | |
| 51 | - | |
| 52 | - SipFactory.getInstance().setPathName("gov.nist"); | |
| 53 | - if (monitorIps.size() > 0) { | |
| 54 | - for (String monitorIp : monitorIps) { | |
| 55 | - addListeningPoint(monitorIp, sipConfig.getPort()); | |
| 56 | - } | |
| 57 | - if (udpSipProviderMap.size() + tcpSipProviderMap.size() == 0) { | |
| 58 | - System.exit(1); | |
| 59 | - } | |
| 60 | - } | |
| 61 | - } | |
| 62 | - | |
| 63 | - private void addListeningPoint(String monitorIp, int port){ | |
| 64 | - SipStackImpl sipStack; | |
| 65 | - try { | |
| 66 | - sipStack = (SipStackImpl)SipFactory.getInstance().createSipStack(DefaultProperties.getProperties("GB28181_SIP", userSetting.getSipLog())); | |
| 67 | - sipStack.setMessageParserFactory(new GbStringMsgParserFactory()); | |
| 68 | - } catch (PeerUnavailableException e) { | |
| 69 | - logger.error("[SIP SERVER] SIP服务启动失败, 监听地址{}失败,请检查ip是否正确", monitorIp); | |
| 70 | - return; | |
| 71 | - } | |
| 72 | - | |
| 73 | - try { | |
| 74 | - ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "TCP"); | |
| 75 | - SipProviderImpl tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint); | |
| 76 | - | |
| 77 | - tcpSipProvider.setDialogErrorsAutomaticallyHandled(); | |
| 78 | - tcpSipProvider.addSipListener(sipProcessorObserver); | |
| 79 | - tcpSipProviderMap.put(monitorIp, tcpSipProvider); | |
| 80 | - logger.info("[SIP SERVER] tcp://{}:{} 启动成功", monitorIp, port); | |
| 81 | - } catch (TransportNotSupportedException | |
| 82 | - | TooManyListenersException | |
| 83 | - | ObjectInUseException | |
| 84 | - | InvalidArgumentException e) { | |
| 85 | - logger.error("[SIP SERVER] tcp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确" | |
| 86 | - , monitorIp, port); | |
| 87 | - } | |
| 88 | - | |
| 89 | - try { | |
| 90 | - ListeningPoint udpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "UDP"); | |
| 91 | - | |
| 92 | - SipProviderImpl udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint); | |
| 93 | - udpSipProvider.addSipListener(sipProcessorObserver); | |
| 94 | - | |
| 95 | - udpSipProviderMap.put(monitorIp, udpSipProvider); | |
| 96 | - | |
| 97 | - logger.info("[SIP SERVER] udp://{}:{} 启动成功", monitorIp, port); | |
| 98 | - } catch (TransportNotSupportedException | |
| 99 | - | TooManyListenersException | |
| 100 | - | ObjectInUseException | |
| 101 | - | InvalidArgumentException e) { | |
| 102 | - logger.error("[SIP SERVER] udp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确" | |
| 103 | - , monitorIp, port); | |
| 104 | - } | |
| 105 | - } | |
| 106 | - | |
| 107 | - public SipProviderImpl getUdpSipProvider(String ip) { | |
| 108 | - if (ObjectUtils.isEmpty(ip)) { | |
| 109 | - return null; | |
| 110 | - } | |
| 111 | - return udpSipProviderMap.get(ip); | |
| 112 | - } | |
| 113 | - | |
| 114 | - public SipProviderImpl getUdpSipProvider() { | |
| 115 | - if (udpSipProviderMap.size() != 1) { | |
| 116 | - return null; | |
| 117 | - } | |
| 118 | - return udpSipProviderMap.values().stream().findFirst().get(); | |
| 119 | - } | |
| 120 | - | |
| 121 | - public SipProviderImpl getTcpSipProvider() { | |
| 122 | - if (tcpSipProviderMap.size() != 1) { | |
| 123 | - return null; | |
| 124 | - } | |
| 125 | - return tcpSipProviderMap.values().stream().findFirst().get(); | |
| 126 | - } | |
| 127 | - | |
| 128 | - public SipProviderImpl getTcpSipProvider(String ip) { | |
| 129 | - if (ObjectUtils.isEmpty(ip)) { | |
| 130 | - return null; | |
| 131 | - } | |
| 132 | - return tcpSipProviderMap.get(ip); | |
| 133 | - } | |
| 134 | - | |
| 135 | - public String getLocalIp(String deviceLocalIp) { | |
| 136 | - if (!ObjectUtils.isEmpty(deviceLocalIp)) { | |
| 137 | - return deviceLocalIp; | |
| 138 | - } | |
| 139 | - return getUdpSipProvider().getListeningPoint().getIPAddress(); | |
| 140 | - } | |
| 141 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.conf.SipConfig; | |
| 4 | +import com.genersoft.iot.vmp.conf.UserSetting; | |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.GbStringMsgParserFactory; | |
| 6 | +import com.genersoft.iot.vmp.gb28181.conf.DefaultProperties; | |
| 7 | +import com.genersoft.iot.vmp.gb28181.transmit.ISIPProcessorObserver; | |
| 8 | +import gov.nist.javax.sip.SipProviderImpl; | |
| 9 | +import gov.nist.javax.sip.SipStackImpl; | |
| 10 | +import org.slf4j.Logger; | |
| 11 | +import org.slf4j.LoggerFactory; | |
| 12 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 13 | +import org.springframework.boot.CommandLineRunner; | |
| 14 | +import org.springframework.core.annotation.Order; | |
| 15 | +import org.springframework.stereotype.Component; | |
| 16 | +import org.springframework.util.ObjectUtils; | |
| 17 | + | |
| 18 | +import javax.sip.*; | |
| 19 | +import java.util.*; | |
| 20 | +import java.util.concurrent.ConcurrentHashMap; | |
| 21 | + | |
| 22 | +@Component | |
| 23 | +@Order(value=10) | |
| 24 | +public class SipLayer implements CommandLineRunner { | |
| 25 | + | |
| 26 | + private final static Logger logger = LoggerFactory.getLogger(SipLayer.class); | |
| 27 | + | |
| 28 | + @Autowired | |
| 29 | + private SipConfig sipConfig; | |
| 30 | + | |
| 31 | + @Autowired | |
| 32 | + private ISIPProcessorObserver sipProcessorObserver; | |
| 33 | + | |
| 34 | + @Autowired | |
| 35 | + private UserSetting userSetting; | |
| 36 | + | |
| 37 | + private final Map<String, SipProviderImpl> tcpSipProviderMap = new ConcurrentHashMap<>(); | |
| 38 | + private final Map<String, SipProviderImpl> udpSipProviderMap = new ConcurrentHashMap<>(); | |
| 39 | + | |
| 40 | + @Override | |
| 41 | + public void run(String... args) { | |
| 42 | + List<String> monitorIps = new ArrayList<>(); | |
| 43 | + // 使用逗号分割多个ip | |
| 44 | + String separator = ","; | |
| 45 | + if (sipConfig.getIp().indexOf(separator) > 0) { | |
| 46 | + String[] split = sipConfig.getIp().split(separator); | |
| 47 | + monitorIps.addAll(Arrays.asList(split)); | |
| 48 | + }else { | |
| 49 | + monitorIps.add(sipConfig.getIp()); | |
| 50 | + } | |
| 51 | + | |
| 52 | + SipFactory.getInstance().setPathName("gov.nist"); | |
| 53 | + if (monitorIps.size() > 0) { | |
| 54 | + for (String monitorIp : monitorIps) { | |
| 55 | + addListeningPoint(monitorIp, sipConfig.getPort()); | |
| 56 | + } | |
| 57 | + if (udpSipProviderMap.size() + tcpSipProviderMap.size() == 0) { | |
| 58 | + System.exit(1); | |
| 59 | + } | |
| 60 | + } | |
| 61 | + } | |
| 62 | + | |
| 63 | + private void addListeningPoint(String monitorIp, int port){ | |
| 64 | + SipStackImpl sipStack; | |
| 65 | + try { | |
| 66 | + sipStack = (SipStackImpl)SipFactory.getInstance().createSipStack(DefaultProperties.getProperties("GB28181_SIP", userSetting.getSipLog())); | |
| 67 | + sipStack.setMessageParserFactory(new GbStringMsgParserFactory()); | |
| 68 | + } catch (PeerUnavailableException e) { | |
| 69 | + logger.error("[SIP SERVER] SIP服务启动失败, 监听地址{}失败,请检查ip是否正确", monitorIp); | |
| 70 | + return; | |
| 71 | + } | |
| 72 | + | |
| 73 | + try { | |
| 74 | + ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "TCP"); | |
| 75 | + SipProviderImpl tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint); | |
| 76 | + | |
| 77 | + tcpSipProvider.setDialogErrorsAutomaticallyHandled(); | |
| 78 | + tcpSipProvider.addSipListener(sipProcessorObserver); | |
| 79 | + tcpSipProviderMap.put(monitorIp, tcpSipProvider); | |
| 80 | + logger.info("[SIP SERVER] tcp://{}:{} 启动成功", monitorIp, port); | |
| 81 | + } catch (TransportNotSupportedException | |
| 82 | + | TooManyListenersException | |
| 83 | + | ObjectInUseException | |
| 84 | + | InvalidArgumentException e) { | |
| 85 | + logger.error("[SIP SERVER] tcp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确" | |
| 86 | + , monitorIp, port); | |
| 87 | + } | |
| 88 | + | |
| 89 | + try { | |
| 90 | + ListeningPoint udpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "UDP"); | |
| 91 | + | |
| 92 | + SipProviderImpl udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint); | |
| 93 | + udpSipProvider.addSipListener(sipProcessorObserver); | |
| 94 | + | |
| 95 | + udpSipProviderMap.put(monitorIp, udpSipProvider); | |
| 96 | + | |
| 97 | + logger.info("[SIP SERVER] udp://{}:{} 启动成功", monitorIp, port); | |
| 98 | + } catch (TransportNotSupportedException | |
| 99 | + | TooManyListenersException | |
| 100 | + | ObjectInUseException | |
| 101 | + | InvalidArgumentException e) { | |
| 102 | + logger.error("[SIP SERVER] udp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确" | |
| 103 | + , monitorIp, port); | |
| 104 | + } | |
| 105 | + } | |
| 106 | + | |
| 107 | + public SipProviderImpl getUdpSipProvider(String ip) { | |
| 108 | + if (ObjectUtils.isEmpty(ip)) { | |
| 109 | + return null; | |
| 110 | + } | |
| 111 | + return udpSipProviderMap.get(ip); | |
| 112 | + } | |
| 113 | + | |
| 114 | + public SipProviderImpl getUdpSipProvider() { | |
| 115 | + if (udpSipProviderMap.size() != 1) { | |
| 116 | + return null; | |
| 117 | + } | |
| 118 | + return udpSipProviderMap.values().stream().findFirst().get(); | |
| 119 | + } | |
| 120 | + | |
| 121 | + public SipProviderImpl getTcpSipProvider() { | |
| 122 | + if (tcpSipProviderMap.size() != 1) { | |
| 123 | + return null; | |
| 124 | + } | |
| 125 | + return tcpSipProviderMap.values().stream().findFirst().get(); | |
| 126 | + } | |
| 127 | + | |
| 128 | + public SipProviderImpl getTcpSipProvider(String ip) { | |
| 129 | + if (ObjectUtils.isEmpty(ip)) { | |
| 130 | + return null; | |
| 131 | + } | |
| 132 | + return tcpSipProviderMap.get(ip); | |
| 133 | + } | |
| 134 | + | |
| 135 | + public String getLocalIp(String deviceLocalIp) { | |
| 136 | + if (!ObjectUtils.isEmpty(deviceLocalIp)) { | |
| 137 | + return deviceLocalIp; | |
| 138 | + } | |
| 139 | + return getUdpSipProvider().getListeningPoint().getIPAddress(); | |
| 140 | + } | |
| 141 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java
| 1 | -package com.genersoft.iot.vmp.gb28181.bean; | |
| 2 | - | |
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | - | |
| 5 | -/** | |
| 6 | - * @author lin | |
| 7 | - */ | |
| 8 | -@Schema(description = "报警信息") | |
| 9 | -public class DeviceAlarm { | |
| 10 | - | |
| 11 | - /** | |
| 12 | - * 数据库id | |
| 13 | - */ | |
| 14 | - @Schema(description = "数据库id") | |
| 15 | - private String id; | |
| 16 | - | |
| 17 | - /** | |
| 18 | - * 设备Id | |
| 19 | - */ | |
| 20 | - @Schema(description = "设备的国标编号") | |
| 21 | - private String deviceId; | |
| 22 | - | |
| 23 | - /** | |
| 24 | - * 通道Id | |
| 25 | - */ | |
| 26 | - @Schema(description = "通道的国标编号") | |
| 27 | - private String channelId; | |
| 28 | - | |
| 29 | - /** | |
| 30 | - * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情 | |
| 31 | - */ | |
| 32 | - @Schema(description = "报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情") | |
| 33 | - private String alarmPriority; | |
| 34 | - | |
| 35 | - /** | |
| 36 | - * 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警, | |
| 37 | - * 7其他报警;可以为直接组合如12为电话报警或 设备报警- | |
| 38 | - */ | |
| 39 | - @Schema(description = "报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,\n" + | |
| 40 | - "\t * 7其他报警;可以为直接组合如12为电话报警或设备报警") | |
| 41 | - private String alarmMethod; | |
| 42 | - | |
| 43 | - /** | |
| 44 | - * 报警时间 | |
| 45 | - */ | |
| 46 | - @Schema(description = "报警时间") | |
| 47 | - private String alarmTime; | |
| 48 | - | |
| 49 | - /** | |
| 50 | - * 报警内容描述 | |
| 51 | - */ | |
| 52 | - @Schema(description = "报警内容描述") | |
| 53 | - private String alarmDescription; | |
| 54 | - | |
| 55 | - /** | |
| 56 | - * 经度 | |
| 57 | - */ | |
| 58 | - @Schema(description = "经度") | |
| 59 | - private double longitude; | |
| 60 | - | |
| 61 | - /** | |
| 62 | - * 纬度 | |
| 63 | - */ | |
| 64 | - @Schema(description = "纬度") | |
| 65 | - private double latitude; | |
| 66 | - | |
| 67 | - /** | |
| 68 | - * 报警类型, | |
| 69 | - * 报警方式为2时,不携带 AlarmType为默认的报警设备报警, | |
| 70 | - * 携带 AlarmType取值及对应报警类型如下: | |
| 71 | - * 1-视频丢失报警; | |
| 72 | - * 2-设备防拆报警; | |
| 73 | - * 3-存储设备磁盘满报警; | |
| 74 | - * 4-设备高温报警; | |
| 75 | - * 5-设备低温报警。 | |
| 76 | - * 报警方式为5时,取值如下: | |
| 77 | - * 1-人工视频报警; | |
| 78 | - * 2-运动目标检测报警; | |
| 79 | - * 3-遗留物检测报警; | |
| 80 | - * 4-物体移除检测报警; | |
| 81 | - * 5-绊线检测报警; | |
| 82 | - * 6-入侵检测报警; | |
| 83 | - * 7-逆行检测报警; | |
| 84 | - * 8-徘徊检测报警; | |
| 85 | - * 9-流量统计报警; | |
| 86 | - * 10-密度检测报警; | |
| 87 | - * 11-视频异常检测报警; | |
| 88 | - * 12-快速移动报警。 | |
| 89 | - * 报警方式为6时,取值下: | |
| 90 | - * 1-存储设备磁盘故障报警; | |
| 91 | - * 2-存储设备风扇故障报警。 | |
| 92 | - */ | |
| 93 | - @Schema(description = "报警类型") | |
| 94 | - private String alarmType; | |
| 95 | - | |
| 96 | - @Schema(description = "创建时间") | |
| 97 | - private String createTime; | |
| 98 | - | |
| 99 | - | |
| 100 | - public String getId() { | |
| 101 | - return id; | |
| 102 | - } | |
| 103 | - | |
| 104 | - public void setId(String id) { | |
| 105 | - this.id = id; | |
| 106 | - } | |
| 107 | - | |
| 108 | - public String getDeviceId() { | |
| 109 | - return deviceId; | |
| 110 | - } | |
| 111 | - | |
| 112 | - public void setDeviceId(String deviceId) { | |
| 113 | - this.deviceId = deviceId; | |
| 114 | - } | |
| 115 | - | |
| 116 | - public String getAlarmPriority() { | |
| 117 | - return alarmPriority; | |
| 118 | - } | |
| 119 | - | |
| 120 | - public void setAlarmPriority(String alarmPriority) { | |
| 121 | - this.alarmPriority = alarmPriority; | |
| 122 | - } | |
| 123 | - | |
| 124 | - public String getAlarmMethod() { | |
| 125 | - return alarmMethod; | |
| 126 | - } | |
| 127 | - | |
| 128 | - public void setAlarmMethod(String alarmMethod) { | |
| 129 | - this.alarmMethod = alarmMethod; | |
| 130 | - } | |
| 131 | - | |
| 132 | - public String getAlarmTime() { | |
| 133 | - return alarmTime; | |
| 134 | - } | |
| 135 | - | |
| 136 | - public void setAlarmTime(String alarmTime) { | |
| 137 | - this.alarmTime = alarmTime; | |
| 138 | - } | |
| 139 | - | |
| 140 | - public String getAlarmDescription() { | |
| 141 | - return alarmDescription; | |
| 142 | - } | |
| 143 | - | |
| 144 | - public void setAlarmDescription(String alarmDescription) { | |
| 145 | - this.alarmDescription = alarmDescription; | |
| 146 | - } | |
| 147 | - | |
| 148 | - public double getLongitude() { | |
| 149 | - return longitude; | |
| 150 | - } | |
| 151 | - | |
| 152 | - public void setLongitude(double longitude) { | |
| 153 | - this.longitude = longitude; | |
| 154 | - } | |
| 155 | - | |
| 156 | - public double getLatitude() { | |
| 157 | - return latitude; | |
| 158 | - } | |
| 159 | - | |
| 160 | - public void setLatitude(double latitude) { | |
| 161 | - this.latitude = latitude; | |
| 162 | - } | |
| 163 | - | |
| 164 | - public String getAlarmType() { | |
| 165 | - return alarmType; | |
| 166 | - } | |
| 167 | - | |
| 168 | - public void setAlarmType(String alarmType) { | |
| 169 | - this.alarmType = alarmType; | |
| 170 | - } | |
| 171 | - | |
| 172 | - public String getChannelId() { | |
| 173 | - return channelId; | |
| 174 | - } | |
| 175 | - | |
| 176 | - public void setChannelId(String channelId) { | |
| 177 | - this.channelId = channelId; | |
| 178 | - } | |
| 179 | - | |
| 180 | - public String getCreateTime() { | |
| 181 | - return createTime; | |
| 182 | - } | |
| 183 | - | |
| 184 | - public void setCreateTime(String createTime) { | |
| 185 | - this.createTime = createTime; | |
| 186 | - } | |
| 187 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181.bean; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * @author lin | |
| 7 | + */ | |
| 8 | +@Schema(description = "报警信息") | |
| 9 | +public class DeviceAlarm { | |
| 10 | + | |
| 11 | + /** | |
| 12 | + * 数据库id | |
| 13 | + */ | |
| 14 | + @Schema(description = "数据库id") | |
| 15 | + private String id; | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 设备Id | |
| 19 | + */ | |
| 20 | + @Schema(description = "设备的国标编号") | |
| 21 | + private String deviceId; | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 通道Id | |
| 25 | + */ | |
| 26 | + @Schema(description = "通道的国标编号") | |
| 27 | + private String channelId; | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情 | |
| 31 | + */ | |
| 32 | + @Schema(description = "报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情") | |
| 33 | + private String alarmPriority; | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警, | |
| 37 | + * 7其他报警;可以为直接组合如12为电话报警或 设备报警- | |
| 38 | + */ | |
| 39 | + @Schema(description = "报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,\n" + | |
| 40 | + "\t * 7其他报警;可以为直接组合如12为电话报警或设备报警") | |
| 41 | + private String alarmMethod; | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * 报警时间 | |
| 45 | + */ | |
| 46 | + @Schema(description = "报警时间") | |
| 47 | + private String alarmTime; | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * 报警内容描述 | |
| 51 | + */ | |
| 52 | + @Schema(description = "报警内容描述") | |
| 53 | + private String alarmDescription; | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * 经度 | |
| 57 | + */ | |
| 58 | + @Schema(description = "经度") | |
| 59 | + private double longitude; | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * 纬度 | |
| 63 | + */ | |
| 64 | + @Schema(description = "纬度") | |
| 65 | + private double latitude; | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * 报警类型, | |
| 69 | + * 报警方式为2时,不携带 AlarmType为默认的报警设备报警, | |
| 70 | + * 携带 AlarmType取值及对应报警类型如下: | |
| 71 | + * 1-视频丢失报警; | |
| 72 | + * 2-设备防拆报警; | |
| 73 | + * 3-存储设备磁盘满报警; | |
| 74 | + * 4-设备高温报警; | |
| 75 | + * 5-设备低温报警。 | |
| 76 | + * 报警方式为5时,取值如下: | |
| 77 | + * 1-人工视频报警; | |
| 78 | + * 2-运动目标检测报警; | |
| 79 | + * 3-遗留物检测报警; | |
| 80 | + * 4-物体移除检测报警; | |
| 81 | + * 5-绊线检测报警; | |
| 82 | + * 6-入侵检测报警; | |
| 83 | + * 7-逆行检测报警; | |
| 84 | + * 8-徘徊检测报警; | |
| 85 | + * 9-流量统计报警; | |
| 86 | + * 10-密度检测报警; | |
| 87 | + * 11-视频异常检测报警; | |
| 88 | + * 12-快速移动报警。 | |
| 89 | + * 报警方式为6时,取值下: | |
| 90 | + * 1-存储设备磁盘故障报警; | |
| 91 | + * 2-存储设备风扇故障报警。 | |
| 92 | + */ | |
| 93 | + @Schema(description = "报警类型") | |
| 94 | + private String alarmType; | |
| 95 | + | |
| 96 | + @Schema(description = "创建时间") | |
| 97 | + private String createTime; | |
| 98 | + | |
| 99 | + | |
| 100 | + public String getId() { | |
| 101 | + return id; | |
| 102 | + } | |
| 103 | + | |
| 104 | + public void setId(String id) { | |
| 105 | + this.id = id; | |
| 106 | + } | |
| 107 | + | |
| 108 | + public String getDeviceId() { | |
| 109 | + return deviceId; | |
| 110 | + } | |
| 111 | + | |
| 112 | + public void setDeviceId(String deviceId) { | |
| 113 | + this.deviceId = deviceId; | |
| 114 | + } | |
| 115 | + | |
| 116 | + public String getAlarmPriority() { | |
| 117 | + return alarmPriority; | |
| 118 | + } | |
| 119 | + | |
| 120 | + public void setAlarmPriority(String alarmPriority) { | |
| 121 | + this.alarmPriority = alarmPriority; | |
| 122 | + } | |
| 123 | + | |
| 124 | + public String getAlarmMethod() { | |
| 125 | + return alarmMethod; | |
| 126 | + } | |
| 127 | + | |
| 128 | + public void setAlarmMethod(String alarmMethod) { | |
| 129 | + this.alarmMethod = alarmMethod; | |
| 130 | + } | |
| 131 | + | |
| 132 | + public String getAlarmTime() { | |
| 133 | + return alarmTime; | |
| 134 | + } | |
| 135 | + | |
| 136 | + public void setAlarmTime(String alarmTime) { | |
| 137 | + this.alarmTime = alarmTime; | |
| 138 | + } | |
| 139 | + | |
| 140 | + public String getAlarmDescription() { | |
| 141 | + return alarmDescription; | |
| 142 | + } | |
| 143 | + | |
| 144 | + public void setAlarmDescription(String alarmDescription) { | |
| 145 | + this.alarmDescription = alarmDescription; | |
| 146 | + } | |
| 147 | + | |
| 148 | + public double getLongitude() { | |
| 149 | + return longitude; | |
| 150 | + } | |
| 151 | + | |
| 152 | + public void setLongitude(double longitude) { | |
| 153 | + this.longitude = longitude; | |
| 154 | + } | |
| 155 | + | |
| 156 | + public double getLatitude() { | |
| 157 | + return latitude; | |
| 158 | + } | |
| 159 | + | |
| 160 | + public void setLatitude(double latitude) { | |
| 161 | + this.latitude = latitude; | |
| 162 | + } | |
| 163 | + | |
| 164 | + public String getAlarmType() { | |
| 165 | + return alarmType; | |
| 166 | + } | |
| 167 | + | |
| 168 | + public void setAlarmType(String alarmType) { | |
| 169 | + this.alarmType = alarmType; | |
| 170 | + } | |
| 171 | + | |
| 172 | + public String getChannelId() { | |
| 173 | + return channelId; | |
| 174 | + } | |
| 175 | + | |
| 176 | + public void setChannelId(String channelId) { | |
| 177 | + this.channelId = channelId; | |
| 178 | + } | |
| 179 | + | |
| 180 | + public String getCreateTime() { | |
| 181 | + return createTime; | |
| 182 | + } | |
| 183 | + | |
| 184 | + public void setCreateTime(String createTime) { | |
| 185 | + this.createTime = createTime; | |
| 186 | + } | |
| 187 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GBStringMsgParser.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStringMsgParserFactory.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/HandlerCatchData.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Host.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamCallback.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatformCatch.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformRegister.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PresetQuerySipReq.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.gb28181.bean; | |
| 2 | - | |
| 3 | - | |
| 4 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | - | |
| 6 | -import java.time.Instant; | |
| 7 | -import java.util.List; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * @description:设备录像信息bean | |
| 11 | - * @author: swwheihei | |
| 12 | - * @date: 2020年5月8日 下午2:05:56 | |
| 13 | - */ | |
| 14 | -@Schema(description = "设备录像查询结果信息") | |
| 15 | -public class RecordInfo { | |
| 16 | - | |
| 17 | - @Schema(description = "设备编号") | |
| 18 | - private String deviceId; | |
| 19 | - | |
| 20 | - @Schema(description = "通道编号") | |
| 21 | - private String channelId; | |
| 22 | - | |
| 23 | - @Schema(description = "命令序列号") | |
| 24 | - private String sn; | |
| 25 | - | |
| 26 | - @Schema(description = "设备名称") | |
| 27 | - private String name; | |
| 28 | - | |
| 29 | - @Schema(description = "列表总数") | |
| 30 | - private int sumNum; | |
| 31 | - | |
| 32 | - private int count; | |
| 33 | - | |
| 34 | - private Instant lastTime; | |
| 35 | - | |
| 36 | - @Schema(description = "") | |
| 37 | - private List<RecordItem> recordList; | |
| 38 | - | |
| 39 | - public String getDeviceId() { | |
| 40 | - return deviceId; | |
| 41 | - } | |
| 42 | - | |
| 43 | - public void setDeviceId(String deviceId) { | |
| 44 | - this.deviceId = deviceId; | |
| 45 | - } | |
| 46 | - | |
| 47 | - public String getName() { | |
| 48 | - return name; | |
| 49 | - } | |
| 50 | - | |
| 51 | - public void setName(String name) { | |
| 52 | - this.name = name; | |
| 53 | - } | |
| 54 | - | |
| 55 | - public int getSumNum() { | |
| 56 | - return sumNum; | |
| 57 | - } | |
| 58 | - | |
| 59 | - public void setSumNum(int sumNum) { | |
| 60 | - this.sumNum = sumNum; | |
| 61 | - } | |
| 62 | - | |
| 63 | - public List<RecordItem> getRecordList() { | |
| 64 | - return recordList; | |
| 65 | - } | |
| 66 | - | |
| 67 | - public void setRecordList(List<RecordItem> recordList) { | |
| 68 | - this.recordList = recordList; | |
| 69 | - } | |
| 70 | - | |
| 71 | - public String getChannelId() { | |
| 72 | - return channelId; | |
| 73 | - } | |
| 74 | - | |
| 75 | - public void setChannelId(String channelId) { | |
| 76 | - this.channelId = channelId; | |
| 77 | - } | |
| 78 | - | |
| 79 | - public String getSn() { | |
| 80 | - return sn; | |
| 81 | - } | |
| 82 | - | |
| 83 | - public void setSn(String sn) { | |
| 84 | - this.sn = sn; | |
| 85 | - } | |
| 86 | - | |
| 87 | - public Instant getLastTime() { | |
| 88 | - return lastTime; | |
| 89 | - } | |
| 90 | - | |
| 91 | - public void setLastTime(Instant lastTime) { | |
| 92 | - this.lastTime = lastTime; | |
| 93 | - } | |
| 94 | - | |
| 95 | - public int getCount() { | |
| 96 | - return count; | |
| 97 | - } | |
| 98 | - | |
| 99 | - public void setCount(int count) { | |
| 100 | - this.count = count; | |
| 101 | - } | |
| 102 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181.bean; | |
| 2 | + | |
| 3 | + | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | + | |
| 6 | +import java.time.Instant; | |
| 7 | +import java.util.List; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * @description:设备录像信息bean | |
| 11 | + * @author: swwheihei | |
| 12 | + * @date: 2020年5月8日 下午2:05:56 | |
| 13 | + */ | |
| 14 | +@Schema(description = "设备录像查询结果信息") | |
| 15 | +public class RecordInfo { | |
| 16 | + | |
| 17 | + @Schema(description = "设备编号") | |
| 18 | + private String deviceId; | |
| 19 | + | |
| 20 | + @Schema(description = "通道编号") | |
| 21 | + private String channelId; | |
| 22 | + | |
| 23 | + @Schema(description = "命令序列号") | |
| 24 | + private String sn; | |
| 25 | + | |
| 26 | + @Schema(description = "设备名称") | |
| 27 | + private String name; | |
| 28 | + | |
| 29 | + @Schema(description = "列表总数") | |
| 30 | + private int sumNum; | |
| 31 | + | |
| 32 | + private int count; | |
| 33 | + | |
| 34 | + private Instant lastTime; | |
| 35 | + | |
| 36 | + @Schema(description = "") | |
| 37 | + private List<RecordItem> recordList; | |
| 38 | + | |
| 39 | + public String getDeviceId() { | |
| 40 | + return deviceId; | |
| 41 | + } | |
| 42 | + | |
| 43 | + public void setDeviceId(String deviceId) { | |
| 44 | + this.deviceId = deviceId; | |
| 45 | + } | |
| 46 | + | |
| 47 | + public String getName() { | |
| 48 | + return name; | |
| 49 | + } | |
| 50 | + | |
| 51 | + public void setName(String name) { | |
| 52 | + this.name = name; | |
| 53 | + } | |
| 54 | + | |
| 55 | + public int getSumNum() { | |
| 56 | + return sumNum; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public void setSumNum(int sumNum) { | |
| 60 | + this.sumNum = sumNum; | |
| 61 | + } | |
| 62 | + | |
| 63 | + public List<RecordItem> getRecordList() { | |
| 64 | + return recordList; | |
| 65 | + } | |
| 66 | + | |
| 67 | + public void setRecordList(List<RecordItem> recordList) { | |
| 68 | + this.recordList = recordList; | |
| 69 | + } | |
| 70 | + | |
| 71 | + public String getChannelId() { | |
| 72 | + return channelId; | |
| 73 | + } | |
| 74 | + | |
| 75 | + public void setChannelId(String channelId) { | |
| 76 | + this.channelId = channelId; | |
| 77 | + } | |
| 78 | + | |
| 79 | + public String getSn() { | |
| 80 | + return sn; | |
| 81 | + } | |
| 82 | + | |
| 83 | + public void setSn(String sn) { | |
| 84 | + this.sn = sn; | |
| 85 | + } | |
| 86 | + | |
| 87 | + public Instant getLastTime() { | |
| 88 | + return lastTime; | |
| 89 | + } | |
| 90 | + | |
| 91 | + public void setLastTime(Instant lastTime) { | |
| 92 | + this.lastTime = lastTime; | |
| 93 | + } | |
| 94 | + | |
| 95 | + public int getCount() { | |
| 96 | + return count; | |
| 97 | + } | |
| 98 | + | |
| 99 | + public void setCount(int count) { | |
| 100 | + this.count = count; | |
| 101 | + } | |
| 102 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.gb28181.bean; | |
| 2 | - | |
| 3 | - | |
| 4 | -import com.genersoft.iot.vmp.utils.DateUtil; | |
| 5 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | -import org.jetbrains.annotations.NotNull; | |
| 7 | - | |
| 8 | -import java.time.Instant; | |
| 9 | -import java.time.temporal.TemporalAccessor; | |
| 10 | - | |
| 11 | -/** | |
| 12 | - * @description:设备录像bean | |
| 13 | - * @author: swwheihei | |
| 14 | - * @date: 2020年5月8日 下午2:06:54 | |
| 15 | - */ | |
| 16 | -@Schema(description = "设备录像详情") | |
| 17 | -public class RecordItem implements Comparable<RecordItem>{ | |
| 18 | - | |
| 19 | - @Schema(description = "设备编号") | |
| 20 | - private String deviceId; | |
| 21 | - | |
| 22 | - @Schema(description = "名称") | |
| 23 | - private String name; | |
| 24 | - | |
| 25 | - @Schema(description = "文件路径名 (可选)") | |
| 26 | - private String filePath; | |
| 27 | - | |
| 28 | - @Schema(description = "录像文件大小,单位:Byte(可选)") | |
| 29 | - private String fileSize; | |
| 30 | - | |
| 31 | - @Schema(description = "录像地址(可选)") | |
| 32 | - private String address; | |
| 33 | - | |
| 34 | - @Schema(description = "录像开始时间(可选)") | |
| 35 | - private String startTime; | |
| 36 | - | |
| 37 | - @Schema(description = "录像结束时间(可选)") | |
| 38 | - private String endTime; | |
| 39 | - | |
| 40 | - @Schema(description = "保密属性(必选)缺省为0;0:不涉密,1:涉密") | |
| 41 | - private int secrecy; | |
| 42 | - | |
| 43 | - @Schema(description = "录像产生类型(可选)time或alarm 或 manua") | |
| 44 | - private String type; | |
| 45 | - | |
| 46 | - @Schema(description = "录像触发者ID(可选)") | |
| 47 | - private String recorderId; | |
| 48 | - | |
| 49 | - public String getDeviceId() { | |
| 50 | - return deviceId; | |
| 51 | - } | |
| 52 | - | |
| 53 | - public void setDeviceId(String deviceId) { | |
| 54 | - this.deviceId = deviceId; | |
| 55 | - } | |
| 56 | - | |
| 57 | - public String getName() { | |
| 58 | - return name; | |
| 59 | - } | |
| 60 | - | |
| 61 | - public void setName(String name) { | |
| 62 | - this.name = name; | |
| 63 | - } | |
| 64 | - | |
| 65 | - public String getFilePath() { | |
| 66 | - return filePath; | |
| 67 | - } | |
| 68 | - | |
| 69 | - public void setFilePath(String filePath) { | |
| 70 | - this.filePath = filePath; | |
| 71 | - } | |
| 72 | - | |
| 73 | - public String getAddress() { | |
| 74 | - return address; | |
| 75 | - } | |
| 76 | - | |
| 77 | - public void setAddress(String address) { | |
| 78 | - this.address = address; | |
| 79 | - } | |
| 80 | - | |
| 81 | - public String getStartTime() { | |
| 82 | - return startTime; | |
| 83 | - } | |
| 84 | - | |
| 85 | - public void setStartTime(String startTime) { | |
| 86 | - this.startTime = startTime; | |
| 87 | - } | |
| 88 | - | |
| 89 | - public String getEndTime() { | |
| 90 | - return endTime; | |
| 91 | - } | |
| 92 | - | |
| 93 | - public void setEndTime(String endTime) { | |
| 94 | - this.endTime = endTime; | |
| 95 | - } | |
| 96 | - | |
| 97 | - public int getSecrecy() { | |
| 98 | - return secrecy; | |
| 99 | - } | |
| 100 | - | |
| 101 | - public void setSecrecy(int secrecy) { | |
| 102 | - this.secrecy = secrecy; | |
| 103 | - } | |
| 104 | - | |
| 105 | - public String getType() { | |
| 106 | - return type; | |
| 107 | - } | |
| 108 | - | |
| 109 | - public void setType(String type) { | |
| 110 | - this.type = type; | |
| 111 | - } | |
| 112 | - | |
| 113 | - public String getRecorderId() { | |
| 114 | - return recorderId; | |
| 115 | - } | |
| 116 | - | |
| 117 | - public void setRecorderId(String recorderId) { | |
| 118 | - this.recorderId = recorderId; | |
| 119 | - } | |
| 120 | - | |
| 121 | - public String getFileSize() { | |
| 122 | - return fileSize; | |
| 123 | - } | |
| 124 | - | |
| 125 | - public void setFileSize(String fileSize) { | |
| 126 | - this.fileSize = fileSize; | |
| 127 | - } | |
| 128 | - | |
| 129 | - @Override | |
| 130 | - public int compareTo(@NotNull RecordItem recordItem) { | |
| 131 | - TemporalAccessor startTimeNow = DateUtil.formatter.parse(startTime); | |
| 132 | - TemporalAccessor startTimeParam = DateUtil.formatter.parse(recordItem.getStartTime()); | |
| 133 | - Instant startTimeParamInstant = Instant.from(startTimeParam); | |
| 134 | - Instant startTimeNowInstant = Instant.from(startTimeNow); | |
| 135 | - if (startTimeNowInstant.equals(startTimeParamInstant)) { | |
| 136 | - return 0; | |
| 137 | - }else if (Instant.from(startTimeParam).isAfter(Instant.from(startTimeNow)) ) { | |
| 138 | - return -1; | |
| 139 | - }else { | |
| 140 | - return 1; | |
| 141 | - } | |
| 142 | - | |
| 143 | - } | |
| 144 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181.bean; | |
| 2 | + | |
| 3 | + | |
| 4 | +import com.genersoft.iot.vmp.utils.DateUtil; | |
| 5 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | +import org.jetbrains.annotations.NotNull; | |
| 7 | + | |
| 8 | +import java.time.Instant; | |
| 9 | +import java.time.temporal.TemporalAccessor; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * @description:设备录像bean | |
| 13 | + * @author: swwheihei | |
| 14 | + * @date: 2020年5月8日 下午2:06:54 | |
| 15 | + */ | |
| 16 | +@Schema(description = "设备录像详情") | |
| 17 | +public class RecordItem implements Comparable<RecordItem>{ | |
| 18 | + | |
| 19 | + @Schema(description = "设备编号") | |
| 20 | + private String deviceId; | |
| 21 | + | |
| 22 | + @Schema(description = "名称") | |
| 23 | + private String name; | |
| 24 | + | |
| 25 | + @Schema(description = "文件路径名 (可选)") | |
| 26 | + private String filePath; | |
| 27 | + | |
| 28 | + @Schema(description = "录像文件大小,单位:Byte(可选)") | |
| 29 | + private String fileSize; | |
| 30 | + | |
| 31 | + @Schema(description = "录像地址(可选)") | |
| 32 | + private String address; | |
| 33 | + | |
| 34 | + @Schema(description = "录像开始时间(可选)") | |
| 35 | + private String startTime; | |
| 36 | + | |
| 37 | + @Schema(description = "录像结束时间(可选)") | |
| 38 | + private String endTime; | |
| 39 | + | |
| 40 | + @Schema(description = "保密属性(必选)缺省为0;0:不涉密,1:涉密") | |
| 41 | + private int secrecy; | |
| 42 | + | |
| 43 | + @Schema(description = "录像产生类型(可选)time或alarm 或 manua") | |
| 44 | + private String type; | |
| 45 | + | |
| 46 | + @Schema(description = "录像触发者ID(可选)") | |
| 47 | + private String recorderId; | |
| 48 | + | |
| 49 | + public String getDeviceId() { | |
| 50 | + return deviceId; | |
| 51 | + } | |
| 52 | + | |
| 53 | + public void setDeviceId(String deviceId) { | |
| 54 | + this.deviceId = deviceId; | |
| 55 | + } | |
| 56 | + | |
| 57 | + public String getName() { | |
| 58 | + return name; | |
| 59 | + } | |
| 60 | + | |
| 61 | + public void setName(String name) { | |
| 62 | + this.name = name; | |
| 63 | + } | |
| 64 | + | |
| 65 | + public String getFilePath() { | |
| 66 | + return filePath; | |
| 67 | + } | |
| 68 | + | |
| 69 | + public void setFilePath(String filePath) { | |
| 70 | + this.filePath = filePath; | |
| 71 | + } | |
| 72 | + | |
| 73 | + public String getAddress() { | |
| 74 | + return address; | |
| 75 | + } | |
| 76 | + | |
| 77 | + public void setAddress(String address) { | |
| 78 | + this.address = address; | |
| 79 | + } | |
| 80 | + | |
| 81 | + public String getStartTime() { | |
| 82 | + return startTime; | |
| 83 | + } | |
| 84 | + | |
| 85 | + public void setStartTime(String startTime) { | |
| 86 | + this.startTime = startTime; | |
| 87 | + } | |
| 88 | + | |
| 89 | + public String getEndTime() { | |
| 90 | + return endTime; | |
| 91 | + } | |
| 92 | + | |
| 93 | + public void setEndTime(String endTime) { | |
| 94 | + this.endTime = endTime; | |
| 95 | + } | |
| 96 | + | |
| 97 | + public int getSecrecy() { | |
| 98 | + return secrecy; | |
| 99 | + } | |
| 100 | + | |
| 101 | + public void setSecrecy(int secrecy) { | |
| 102 | + this.secrecy = secrecy; | |
| 103 | + } | |
| 104 | + | |
| 105 | + public String getType() { | |
| 106 | + return type; | |
| 107 | + } | |
| 108 | + | |
| 109 | + public void setType(String type) { | |
| 110 | + this.type = type; | |
| 111 | + } | |
| 112 | + | |
| 113 | + public String getRecorderId() { | |
| 114 | + return recorderId; | |
| 115 | + } | |
| 116 | + | |
| 117 | + public void setRecorderId(String recorderId) { | |
| 118 | + this.recorderId = recorderId; | |
| 119 | + } | |
| 120 | + | |
| 121 | + public String getFileSize() { | |
| 122 | + return fileSize; | |
| 123 | + } | |
| 124 | + | |
| 125 | + public void setFileSize(String fileSize) { | |
| 126 | + this.fileSize = fileSize; | |
| 127 | + } | |
| 128 | + | |
| 129 | + @Override | |
| 130 | + public int compareTo(@NotNull RecordItem recordItem) { | |
| 131 | + TemporalAccessor startTimeNow = DateUtil.formatter.parse(startTime); | |
| 132 | + TemporalAccessor startTimeParam = DateUtil.formatter.parse(recordItem.getStartTime()); | |
| 133 | + Instant startTimeParamInstant = Instant.from(startTimeParam); | |
| 134 | + Instant startTimeNowInstant = Instant.from(startTimeNow); | |
| 135 | + if (startTimeNowInstant.equals(startTimeParamInstant)) { | |
| 136 | + return 0; | |
| 137 | + }else if (Instant.from(startTimeParam).isAfter(Instant.from(startTimeNow)) ) { | |
| 138 | + return -1; | |
| 139 | + }else { | |
| 140 | + return 1; | |
| 141 | + } | |
| 142 | + | |
| 143 | + } | |
| 144 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SDPInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipMsgInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SyncStatus.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/conf/DefaultProperties.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/conf/ServerLoggerImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/conf/StackLoggerImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.gb28181.event; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.gb28181.bean.*; | |
| 4 | -import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent; | |
| 5 | -import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent; | |
| 6 | -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | |
| 7 | -import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent; | |
| 8 | -import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent; | |
| 9 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 10 | -import org.springframework.context.ApplicationEventPublisher; | |
| 11 | -import org.springframework.stereotype.Component; | |
| 12 | - | |
| 13 | -import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent; | |
| 14 | - | |
| 15 | -import javax.sip.TimeoutEvent; | |
| 16 | -import java.util.ArrayList; | |
| 17 | -import java.util.HashSet; | |
| 18 | -import java.util.List; | |
| 19 | -import java.util.Set; | |
| 20 | - | |
| 21 | -/** | |
| 22 | - * @description:Event事件通知推送器,支持推送在线事件、离线事件 | |
| 23 | - * @author: swwheihei | |
| 24 | - * @date: 2020年5月6日 上午11:30:50 | |
| 25 | - */ | |
| 26 | -@Component | |
| 27 | -public class EventPublisher { | |
| 28 | - | |
| 29 | - @Autowired | |
| 30 | - private ApplicationEventPublisher applicationEventPublisher; | |
| 31 | - | |
| 32 | - /** | |
| 33 | - * 设备报警事件 | |
| 34 | - * @param deviceAlarm | |
| 35 | - */ | |
| 36 | - public void deviceAlarmEventPublish(DeviceAlarm deviceAlarm) { | |
| 37 | - AlarmEvent alarmEvent = new AlarmEvent(this); | |
| 38 | - alarmEvent.setAlarmInfo(deviceAlarm); | |
| 39 | - applicationEventPublisher.publishEvent(alarmEvent); | |
| 40 | - } | |
| 41 | - | |
| 42 | - public void zlmOfflineEventPublish(String mediaServerId){ | |
| 43 | - ZLMOfflineEvent outEvent = new ZLMOfflineEvent(this); | |
| 44 | - outEvent.setMediaServerId(mediaServerId); | |
| 45 | - applicationEventPublisher.publishEvent(outEvent); | |
| 46 | - } | |
| 47 | - | |
| 48 | - public void zlmOnlineEventPublish(String mediaServerId) { | |
| 49 | - ZLMOnlineEvent outEvent = new ZLMOnlineEvent(this); | |
| 50 | - outEvent.setMediaServerId(mediaServerId); | |
| 51 | - applicationEventPublisher.publishEvent(outEvent); | |
| 52 | - } | |
| 53 | - | |
| 54 | - | |
| 55 | - public void catalogEventPublish(String platformId, DeviceChannel deviceChannel, String type) { | |
| 56 | - List<DeviceChannel> deviceChannelList = new ArrayList<>(); | |
| 57 | - deviceChannelList.add(deviceChannel); | |
| 58 | - catalogEventPublish(platformId, deviceChannelList, type); | |
| 59 | - } | |
| 60 | - | |
| 61 | - | |
| 62 | - public void requestTimeOut(TimeoutEvent timeoutEvent) { | |
| 63 | - RequestTimeoutEvent requestTimeoutEvent = new RequestTimeoutEvent(this); | |
| 64 | - requestTimeoutEvent.setTimeoutEvent(timeoutEvent); | |
| 65 | - applicationEventPublisher.publishEvent(requestTimeoutEvent); | |
| 66 | - } | |
| 67 | - | |
| 68 | - | |
| 69 | - /** | |
| 70 | - * | |
| 71 | - * @param platformId | |
| 72 | - * @param deviceChannels | |
| 73 | - * @param type | |
| 74 | - */ | |
| 75 | - public void catalogEventPublish(String platformId, List<DeviceChannel> deviceChannels, String type) { | |
| 76 | - CatalogEvent outEvent = new CatalogEvent(this); | |
| 77 | - List<DeviceChannel> channels = new ArrayList<>(); | |
| 78 | - if (deviceChannels.size() > 1) { | |
| 79 | - // 数据去重 | |
| 80 | - Set<String> gbIdSet = new HashSet<>(); | |
| 81 | - for (DeviceChannel deviceChannel : deviceChannels) { | |
| 82 | - if (!gbIdSet.contains(deviceChannel.getChannelId())) { | |
| 83 | - gbIdSet.add(deviceChannel.getChannelId()); | |
| 84 | - channels.add(deviceChannel); | |
| 85 | - } | |
| 86 | - } | |
| 87 | - }else { | |
| 88 | - channels = deviceChannels; | |
| 89 | - } | |
| 90 | - outEvent.setDeviceChannels(channels); | |
| 91 | - outEvent.setType(type); | |
| 92 | - outEvent.setPlatformId(platformId); | |
| 93 | - applicationEventPublisher.publishEvent(outEvent); | |
| 94 | - } | |
| 95 | - | |
| 96 | - | |
| 97 | - public void catalogEventPublishForStream(String platformId, List<GbStream> gbStreams, String type) { | |
| 98 | - CatalogEvent outEvent = new CatalogEvent(this); | |
| 99 | - outEvent.setGbStreams(gbStreams); | |
| 100 | - outEvent.setType(type); | |
| 101 | - outEvent.setPlatformId(platformId); | |
| 102 | - applicationEventPublisher.publishEvent(outEvent); | |
| 103 | - } | |
| 104 | - | |
| 105 | - | |
| 106 | - public void catalogEventPublishForStream(String platformId, GbStream gbStream, String type) { | |
| 107 | - List<GbStream> gbStreamList = new ArrayList<>(); | |
| 108 | - gbStreamList.add(gbStream); | |
| 109 | - catalogEventPublishForStream(platformId, gbStreamList, type); | |
| 110 | - } | |
| 111 | - | |
| 112 | - public void recordEndEventPush(RecordInfo recordInfo) { | |
| 113 | - RecordEndEvent outEvent = new RecordEndEvent(this); | |
| 114 | - outEvent.setRecordInfo(recordInfo); | |
| 115 | - applicationEventPublisher.publishEvent(outEvent); | |
| 116 | - } | |
| 117 | - | |
| 118 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181.event; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.gb28181.bean.*; | |
| 4 | +import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent; | |
| 5 | +import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent; | |
| 6 | +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | |
| 7 | +import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent; | |
| 8 | +import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent; | |
| 9 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 10 | +import org.springframework.context.ApplicationEventPublisher; | |
| 11 | +import org.springframework.stereotype.Component; | |
| 12 | + | |
| 13 | +import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent; | |
| 14 | + | |
| 15 | +import javax.sip.TimeoutEvent; | |
| 16 | +import java.util.ArrayList; | |
| 17 | +import java.util.HashSet; | |
| 18 | +import java.util.List; | |
| 19 | +import java.util.Set; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * @description:Event事件通知推送器,支持推送在线事件、离线事件 | |
| 23 | + * @author: swwheihei | |
| 24 | + * @date: 2020年5月6日 上午11:30:50 | |
| 25 | + */ | |
| 26 | +@Component | |
| 27 | +public class EventPublisher { | |
| 28 | + | |
| 29 | + @Autowired | |
| 30 | + private ApplicationEventPublisher applicationEventPublisher; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * 设备报警事件 | |
| 34 | + * @param deviceAlarm | |
| 35 | + */ | |
| 36 | + public void deviceAlarmEventPublish(DeviceAlarm deviceAlarm) { | |
| 37 | + AlarmEvent alarmEvent = new AlarmEvent(this); | |
| 38 | + alarmEvent.setAlarmInfo(deviceAlarm); | |
| 39 | + applicationEventPublisher.publishEvent(alarmEvent); | |
| 40 | + } | |
| 41 | + | |
| 42 | + public void zlmOfflineEventPublish(String mediaServerId){ | |
| 43 | + ZLMOfflineEvent outEvent = new ZLMOfflineEvent(this); | |
| 44 | + outEvent.setMediaServerId(mediaServerId); | |
| 45 | + applicationEventPublisher.publishEvent(outEvent); | |
| 46 | + } | |
| 47 | + | |
| 48 | + public void zlmOnlineEventPublish(String mediaServerId) { | |
| 49 | + ZLMOnlineEvent outEvent = new ZLMOnlineEvent(this); | |
| 50 | + outEvent.setMediaServerId(mediaServerId); | |
| 51 | + applicationEventPublisher.publishEvent(outEvent); | |
| 52 | + } | |
| 53 | + | |
| 54 | + | |
| 55 | + public void catalogEventPublish(String platformId, DeviceChannel deviceChannel, String type) { | |
| 56 | + List<DeviceChannel> deviceChannelList = new ArrayList<>(); | |
| 57 | + deviceChannelList.add(deviceChannel); | |
| 58 | + catalogEventPublish(platformId, deviceChannelList, type); | |
| 59 | + } | |
| 60 | + | |
| 61 | + | |
| 62 | + public void requestTimeOut(TimeoutEvent timeoutEvent) { | |
| 63 | + RequestTimeoutEvent requestTimeoutEvent = new RequestTimeoutEvent(this); | |
| 64 | + requestTimeoutEvent.setTimeoutEvent(timeoutEvent); | |
| 65 | + applicationEventPublisher.publishEvent(requestTimeoutEvent); | |
| 66 | + } | |
| 67 | + | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * | |
| 71 | + * @param platformId | |
| 72 | + * @param deviceChannels | |
| 73 | + * @param type | |
| 74 | + */ | |
| 75 | + public void catalogEventPublish(String platformId, List<DeviceChannel> deviceChannels, String type) { | |
| 76 | + CatalogEvent outEvent = new CatalogEvent(this); | |
| 77 | + List<DeviceChannel> channels = new ArrayList<>(); | |
| 78 | + if (deviceChannels.size() > 1) { | |
| 79 | + // 数据去重 | |
| 80 | + Set<String> gbIdSet = new HashSet<>(); | |
| 81 | + for (DeviceChannel deviceChannel : deviceChannels) { | |
| 82 | + if (!gbIdSet.contains(deviceChannel.getChannelId())) { | |
| 83 | + gbIdSet.add(deviceChannel.getChannelId()); | |
| 84 | + channels.add(deviceChannel); | |
| 85 | + } | |
| 86 | + } | |
| 87 | + }else { | |
| 88 | + channels = deviceChannels; | |
| 89 | + } | |
| 90 | + outEvent.setDeviceChannels(channels); | |
| 91 | + outEvent.setType(type); | |
| 92 | + outEvent.setPlatformId(platformId); | |
| 93 | + applicationEventPublisher.publishEvent(outEvent); | |
| 94 | + } | |
| 95 | + | |
| 96 | + | |
| 97 | + public void catalogEventPublishForStream(String platformId, List<GbStream> gbStreams, String type) { | |
| 98 | + CatalogEvent outEvent = new CatalogEvent(this); | |
| 99 | + outEvent.setGbStreams(gbStreams); | |
| 100 | + outEvent.setType(type); | |
| 101 | + outEvent.setPlatformId(platformId); | |
| 102 | + applicationEventPublisher.publishEvent(outEvent); | |
| 103 | + } | |
| 104 | + | |
| 105 | + | |
| 106 | + public void catalogEventPublishForStream(String platformId, GbStream gbStream, String type) { | |
| 107 | + List<GbStream> gbStreamList = new ArrayList<>(); | |
| 108 | + gbStreamList.add(gbStream); | |
| 109 | + catalogEventPublishForStream(platformId, gbStreamList, type); | |
| 110 | + } | |
| 111 | + | |
| 112 | + public void recordEndEventPush(RecordInfo recordInfo) { | |
| 113 | + RecordEndEvent outEvent = new RecordEndEvent(this); | |
| 114 | + outEvent.setRecordInfo(recordInfo); | |
| 115 | + applicationEventPublisher.publishEvent(outEvent); | |
| 116 | + } | |
| 117 | + | |
| 118 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEvent.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEvent.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.gb28181.session; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.common.InviteSessionType; | |
| 4 | -import com.genersoft.iot.vmp.common.VideoManagerConstants; | |
| 5 | -import com.genersoft.iot.vmp.conf.UserSetting; | |
| 6 | -import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; | |
| 7 | -import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; | |
| 8 | -import com.genersoft.iot.vmp.utils.JsonUtil; | |
| 9 | -import com.genersoft.iot.vmp.utils.redis.RedisUtil; | |
| 10 | -import gov.nist.javax.sip.message.SIPResponse; | |
| 11 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 12 | -import org.springframework.data.redis.core.RedisTemplate; | |
| 13 | -import org.springframework.stereotype.Component; | |
| 14 | -import org.springframework.util.ObjectUtils; | |
| 15 | - | |
| 16 | -import java.util.ArrayList; | |
| 17 | -import java.util.List; | |
| 18 | - | |
| 19 | -/** | |
| 20 | - * 视频流session管理器,管理视频预览、预览回放的通信句柄 | |
| 21 | - */ | |
| 22 | -@Component | |
| 23 | -public class VideoStreamSessionManager { | |
| 24 | - | |
| 25 | - @Autowired | |
| 26 | - private UserSetting userSetting; | |
| 27 | - | |
| 28 | - @Autowired | |
| 29 | - private RedisTemplate<Object, Object> redisTemplate; | |
| 30 | - | |
| 31 | - /** | |
| 32 | - * 添加一个点播/回放的事务信息 | |
| 33 | - * 后续可以通过流Id/callID | |
| 34 | - * @param deviceId 设备ID | |
| 35 | - * @param channelId 通道ID | |
| 36 | - * @param callId 一次请求的CallID | |
| 37 | - * @param stream 流名称 | |
| 38 | - * @param mediaServerId 所使用的流媒体ID | |
| 39 | - * @param response 回复 | |
| 40 | - */ | |
| 41 | - public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, InviteSessionType type){ | |
| 42 | - SsrcTransaction ssrcTransaction = new SsrcTransaction(); | |
| 43 | - ssrcTransaction.setDeviceId(deviceId); | |
| 44 | - ssrcTransaction.setChannelId(channelId); | |
| 45 | - ssrcTransaction.setStream(stream); | |
| 46 | - ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo(response)); | |
| 47 | - ssrcTransaction.setCallId(callId); | |
| 48 | - ssrcTransaction.setSsrc(ssrc); | |
| 49 | - ssrcTransaction.setMediaServerId(mediaServerId); | |
| 50 | - ssrcTransaction.setType(type); | |
| 51 | - | |
| 52 | - redisTemplate.opsForValue().set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() | |
| 53 | - + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction); | |
| 54 | - } | |
| 55 | - | |
| 56 | - public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){ | |
| 57 | - | |
| 58 | - if (ObjectUtils.isEmpty(deviceId)) { | |
| 59 | - deviceId ="*"; | |
| 60 | - } | |
| 61 | - if (ObjectUtils.isEmpty(channelId)) { | |
| 62 | - channelId ="*"; | |
| 63 | - } | |
| 64 | - if (ObjectUtils.isEmpty(callId)) { | |
| 65 | - callId ="*"; | |
| 66 | - } | |
| 67 | - if (ObjectUtils.isEmpty(stream)) { | |
| 68 | - stream ="*"; | |
| 69 | - } | |
| 70 | - String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; | |
| 71 | - List<Object> scanResult = RedisUtil.scan(redisTemplate, key); | |
| 72 | - if (scanResult.size() == 0) { | |
| 73 | - return null; | |
| 74 | - } | |
| 75 | - return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); | |
| 76 | - } | |
| 77 | - | |
| 78 | - public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){ | |
| 79 | - if (ObjectUtils.isEmpty(deviceId)) { | |
| 80 | - deviceId ="*"; | |
| 81 | - } | |
| 82 | - if (ObjectUtils.isEmpty(channelId)) { | |
| 83 | - channelId ="*"; | |
| 84 | - } | |
| 85 | - if (ObjectUtils.isEmpty(callId)) { | |
| 86 | - callId ="*"; | |
| 87 | - } | |
| 88 | - if (ObjectUtils.isEmpty(stream)) { | |
| 89 | - stream ="*"; | |
| 90 | - } | |
| 91 | - String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; | |
| 92 | - List<Object> scanResult = RedisUtil.scan(redisTemplate, key); | |
| 93 | - if (scanResult.size() == 0) { | |
| 94 | - return null; | |
| 95 | - } | |
| 96 | - List<SsrcTransaction> result = new ArrayList<>(); | |
| 97 | - for (Object keyObj : scanResult) { | |
| 98 | - result.add((SsrcTransaction)redisTemplate.opsForValue().get(keyObj)); | |
| 99 | - } | |
| 100 | - return result; | |
| 101 | - } | |
| 102 | - | |
| 103 | - public String getMediaServerId(String deviceId, String channelId, String stream){ | |
| 104 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 105 | - if (ssrcTransaction == null) { | |
| 106 | - return null; | |
| 107 | - } | |
| 108 | - return ssrcTransaction.getMediaServerId(); | |
| 109 | - } | |
| 110 | - | |
| 111 | - public String getSSRC(String deviceId, String channelId, String stream){ | |
| 112 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 113 | - if (ssrcTransaction == null) { | |
| 114 | - return null; | |
| 115 | - } | |
| 116 | - return ssrcTransaction.getSsrc(); | |
| 117 | - } | |
| 118 | - | |
| 119 | - public void remove(String deviceId, String channelId, String stream) { | |
| 120 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 121 | - if (ssrcTransaction == null) { | |
| 122 | - return; | |
| 123 | - } | |
| 124 | - redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" | |
| 125 | - + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream()); | |
| 126 | - } | |
| 127 | - | |
| 128 | - | |
| 129 | - public List<SsrcTransaction> getAllSsrc() { | |
| 130 | - List<Object> ssrcTransactionKeys = RedisUtil.scan(redisTemplate, String.format("%s_*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetting.getServerId())); | |
| 131 | - List<SsrcTransaction> result= new ArrayList<>(); | |
| 132 | - for (Object ssrcTransactionKey : ssrcTransactionKeys) { | |
| 133 | - String key = (String) ssrcTransactionKey; | |
| 134 | - SsrcTransaction ssrcTransaction = JsonUtil.redisJsonToObject(redisTemplate, key, SsrcTransaction.class); | |
| 135 | - result.add(ssrcTransaction); | |
| 136 | - } | |
| 137 | - return result; | |
| 138 | - } | |
| 139 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181.session; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.common.InviteSessionType; | |
| 4 | +import com.genersoft.iot.vmp.common.VideoManagerConstants; | |
| 5 | +import com.genersoft.iot.vmp.conf.UserSetting; | |
| 6 | +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; | |
| 7 | +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; | |
| 8 | +import com.genersoft.iot.vmp.utils.JsonUtil; | |
| 9 | +import com.genersoft.iot.vmp.utils.redis.RedisUtil; | |
| 10 | +import gov.nist.javax.sip.message.SIPResponse; | |
| 11 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 12 | +import org.springframework.data.redis.core.RedisTemplate; | |
| 13 | +import org.springframework.stereotype.Component; | |
| 14 | +import org.springframework.util.ObjectUtils; | |
| 15 | + | |
| 16 | +import java.util.ArrayList; | |
| 17 | +import java.util.List; | |
| 18 | + | |
| 19 | +/** | |
| 20 | + * 视频流session管理器,管理视频预览、预览回放的通信句柄 | |
| 21 | + */ | |
| 22 | +@Component | |
| 23 | +public class VideoStreamSessionManager { | |
| 24 | + | |
| 25 | + @Autowired | |
| 26 | + private UserSetting userSetting; | |
| 27 | + | |
| 28 | + @Autowired | |
| 29 | + private RedisTemplate<Object, Object> redisTemplate; | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * 添加一个点播/回放的事务信息 | |
| 33 | + * 后续可以通过流Id/callID | |
| 34 | + * @param deviceId 设备ID | |
| 35 | + * @param channelId 通道ID | |
| 36 | + * @param callId 一次请求的CallID | |
| 37 | + * @param stream 流名称 | |
| 38 | + * @param mediaServerId 所使用的流媒体ID | |
| 39 | + * @param response 回复 | |
| 40 | + */ | |
| 41 | + public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, InviteSessionType type){ | |
| 42 | + SsrcTransaction ssrcTransaction = new SsrcTransaction(); | |
| 43 | + ssrcTransaction.setDeviceId(deviceId); | |
| 44 | + ssrcTransaction.setChannelId(channelId); | |
| 45 | + ssrcTransaction.setStream(stream); | |
| 46 | + ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo(response)); | |
| 47 | + ssrcTransaction.setCallId(callId); | |
| 48 | + ssrcTransaction.setSsrc(ssrc); | |
| 49 | + ssrcTransaction.setMediaServerId(mediaServerId); | |
| 50 | + ssrcTransaction.setType(type); | |
| 51 | + | |
| 52 | + redisTemplate.opsForValue().set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() | |
| 53 | + + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction); | |
| 54 | + } | |
| 55 | + | |
| 56 | + public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){ | |
| 57 | + | |
| 58 | + if (ObjectUtils.isEmpty(deviceId)) { | |
| 59 | + deviceId ="*"; | |
| 60 | + } | |
| 61 | + if (ObjectUtils.isEmpty(channelId)) { | |
| 62 | + channelId ="*"; | |
| 63 | + } | |
| 64 | + if (ObjectUtils.isEmpty(callId)) { | |
| 65 | + callId ="*"; | |
| 66 | + } | |
| 67 | + if (ObjectUtils.isEmpty(stream)) { | |
| 68 | + stream ="*"; | |
| 69 | + } | |
| 70 | + String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; | |
| 71 | + List<Object> scanResult = RedisUtil.scan(redisTemplate, key); | |
| 72 | + if (scanResult.size() == 0) { | |
| 73 | + return null; | |
| 74 | + } | |
| 75 | + return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); | |
| 76 | + } | |
| 77 | + | |
| 78 | + public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){ | |
| 79 | + if (ObjectUtils.isEmpty(deviceId)) { | |
| 80 | + deviceId ="*"; | |
| 81 | + } | |
| 82 | + if (ObjectUtils.isEmpty(channelId)) { | |
| 83 | + channelId ="*"; | |
| 84 | + } | |
| 85 | + if (ObjectUtils.isEmpty(callId)) { | |
| 86 | + callId ="*"; | |
| 87 | + } | |
| 88 | + if (ObjectUtils.isEmpty(stream)) { | |
| 89 | + stream ="*"; | |
| 90 | + } | |
| 91 | + String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; | |
| 92 | + List<Object> scanResult = RedisUtil.scan(redisTemplate, key); | |
| 93 | + if (scanResult.size() == 0) { | |
| 94 | + return null; | |
| 95 | + } | |
| 96 | + List<SsrcTransaction> result = new ArrayList<>(); | |
| 97 | + for (Object keyObj : scanResult) { | |
| 98 | + result.add((SsrcTransaction)redisTemplate.opsForValue().get(keyObj)); | |
| 99 | + } | |
| 100 | + return result; | |
| 101 | + } | |
| 102 | + | |
| 103 | + public String getMediaServerId(String deviceId, String channelId, String stream){ | |
| 104 | + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 105 | + if (ssrcTransaction == null) { | |
| 106 | + return null; | |
| 107 | + } | |
| 108 | + return ssrcTransaction.getMediaServerId(); | |
| 109 | + } | |
| 110 | + | |
| 111 | + public String getSSRC(String deviceId, String channelId, String stream){ | |
| 112 | + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 113 | + if (ssrcTransaction == null) { | |
| 114 | + return null; | |
| 115 | + } | |
| 116 | + return ssrcTransaction.getSsrc(); | |
| 117 | + } | |
| 118 | + | |
| 119 | + public void remove(String deviceId, String channelId, String stream) { | |
| 120 | + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 121 | + if (ssrcTransaction == null) { | |
| 122 | + return; | |
| 123 | + } | |
| 124 | + redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" | |
| 125 | + + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream()); | |
| 126 | + } | |
| 127 | + | |
| 128 | + | |
| 129 | + public List<SsrcTransaction> getAllSsrc() { | |
| 130 | + List<Object> ssrcTransactionKeys = RedisUtil.scan(redisTemplate, String.format("%s_*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetting.getServerId())); | |
| 131 | + List<SsrcTransaction> result= new ArrayList<>(); | |
| 132 | + for (Object ssrcTransactionKey : ssrcTransactionKeys) { | |
| 133 | + String key = (String) ssrcTransactionKey; | |
| 134 | + SsrcTransaction ssrcTransaction = JsonUtil.redisJsonToObject(redisTemplate, key, SsrcTransaction.class); | |
| 135 | + result.add(ssrcTransaction); | |
| 136 | + } | |
| 137 | + return result; | |
| 138 | + } | |
| 139 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
100644 → 100755
| ... | ... | @@ -12,13 +12,19 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 12 | 12 | import com.genersoft.iot.vmp.service.IDeviceService; |
| 13 | 13 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 14 | 14 | import com.genersoft.iot.vmp.service.IPlatformService; |
| 15 | +import com.genersoft.iot.vmp.service.impl.PlatformServiceImpl; | |
| 15 | 16 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 16 | 17 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 18 | +import org.slf4j.Logger; | |
| 19 | +import org.slf4j.LoggerFactory; | |
| 17 | 20 | import org.springframework.beans.factory.annotation.Autowired; |
| 18 | 21 | import org.springframework.boot.CommandLineRunner; |
| 19 | 22 | import org.springframework.core.annotation.Order; |
| 20 | 23 | import org.springframework.stereotype.Component; |
| 21 | 24 | |
| 25 | +import javax.sip.InvalidArgumentException; | |
| 26 | +import javax.sip.SipException; | |
| 27 | +import java.text.ParseException; | |
| 22 | 28 | import java.util.HashMap; |
| 23 | 29 | import java.util.List; |
| 24 | 30 | import java.util.Map; |
| ... | ... | @@ -59,6 +65,8 @@ public class SipRunner implements CommandLineRunner { |
| 59 | 65 | @Autowired |
| 60 | 66 | private ISIPCommanderForPlatform commanderForPlatform; |
| 61 | 67 | |
| 68 | + private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class); | |
| 69 | + | |
| 62 | 70 | @Override |
| 63 | 71 | public void run(String... args) throws Exception { |
| 64 | 72 | List<Device> deviceList = deviceService.getAllOnlineDevice(); |
| ... | ... | @@ -110,7 +118,11 @@ public class SipRunner implements CommandLineRunner { |
| 110 | 118 | if (jsonObject != null && jsonObject.getInteger("code") == 0) { |
| 111 | 119 | ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId()); |
| 112 | 120 | if (platform != null) { |
| 113 | - commanderForPlatform.streamByeCmd(platform, sendRtpItem.getCallId()); | |
| 121 | + try { | |
| 122 | + commanderForPlatform.streamByeCmd(platform, sendRtpItem.getCallId()); | |
| 123 | + } catch (InvalidArgumentException | ParseException | SipException e) { | |
| 124 | + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | |
| 125 | + } | |
| 114 | 126 | } |
| 115 | 127 | } |
| 116 | 128 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.gb28181.transmit.callback; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx; | |
| 4 | -import org.springframework.stereotype.Component; | |
| 5 | -import org.springframework.util.ObjectUtils; | |
| 6 | -import org.springframework.web.context.request.async.DeferredResult; | |
| 7 | - | |
| 8 | -import java.util.Collection; | |
| 9 | -import java.util.Map; | |
| 10 | -import java.util.Set; | |
| 11 | -import java.util.concurrent.ConcurrentHashMap; | |
| 12 | - | |
| 13 | -/** | |
| 14 | - * @description: 异步请求处理 | |
| 15 | - * @author: swwheihei | |
| 16 | - * @date: 2020年5月8日 下午7:59:05 | |
| 17 | - */ | |
| 18 | -@SuppressWarnings(value = {"rawtypes", "unchecked"}) | |
| 19 | -@Component | |
| 20 | -public class DeferredResultHolder { | |
| 21 | - | |
| 22 | - public static final String CALLBACK_CMD_DEVICESTATUS = "CALLBACK_DEVICESTATUS"; | |
| 23 | - | |
| 24 | - public static final String CALLBACK_CMD_DEVICEINFO = "CALLBACK_DEVICEINFO"; | |
| 25 | - | |
| 26 | - public static final String CALLBACK_CMD_DEVICECONTROL = "CALLBACK_DEVICECONTROL"; | |
| 27 | - | |
| 28 | - public static final String CALLBACK_CMD_DEVICECONFIG = "CALLBACK_DEVICECONFIG"; | |
| 29 | - | |
| 30 | - public static final String CALLBACK_CMD_CONFIGDOWNLOAD = "CALLBACK_CONFIGDOWNLOAD"; | |
| 31 | - | |
| 32 | - public static final String CALLBACK_CMD_CATALOG = "CALLBACK_CATALOG"; | |
| 33 | - | |
| 34 | - public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO"; | |
| 35 | - | |
| 36 | - public static final String CALLBACK_CMD_PLAY = "CALLBACK_PLAY"; | |
| 37 | - | |
| 38 | - public static final String CALLBACK_CMD_PLAYBACK = "CALLBACK_PLAYBACK"; | |
| 39 | - | |
| 40 | - public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD"; | |
| 41 | - | |
| 42 | - public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY"; | |
| 43 | - | |
| 44 | - public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; | |
| 45 | - | |
| 46 | - public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL"; | |
| 47 | - | |
| 48 | - public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION"; | |
| 49 | - | |
| 50 | - public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY"; | |
| 51 | - | |
| 52 | - public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM"; | |
| 53 | - | |
| 54 | - public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST"; | |
| 55 | - | |
| 56 | - public static final String CALLBACK_CMD_SNAP= "CALLBACK_SNAP"; | |
| 57 | - | |
| 58 | - private Map<String, Map<String, DeferredResultEx>> map = new ConcurrentHashMap<>(); | |
| 59 | - | |
| 60 | - | |
| 61 | - public void put(String key, String id, DeferredResultEx result) { | |
| 62 | - Map<String, DeferredResultEx> deferredResultMap = map.get(key); | |
| 63 | - if (deferredResultMap == null) { | |
| 64 | - deferredResultMap = new ConcurrentHashMap<>(); | |
| 65 | - map.put(key, deferredResultMap); | |
| 66 | - } | |
| 67 | - deferredResultMap.put(id, result); | |
| 68 | - } | |
| 69 | - | |
| 70 | - public void put(String key, String id, DeferredResult result) { | |
| 71 | - Map<String, DeferredResultEx> deferredResultMap = map.get(key); | |
| 72 | - if (deferredResultMap == null) { | |
| 73 | - deferredResultMap = new ConcurrentHashMap<>(); | |
| 74 | - map.put(key, deferredResultMap); | |
| 75 | - } | |
| 76 | - deferredResultMap.put(id, new DeferredResultEx(result)); | |
| 77 | - } | |
| 78 | - | |
| 79 | - public DeferredResultEx get(String key, String id) { | |
| 80 | - Map<String, DeferredResultEx> deferredResultMap = map.get(key); | |
| 81 | - if (deferredResultMap == null || ObjectUtils.isEmpty(id)) { | |
| 82 | - return null; | |
| 83 | - } | |
| 84 | - return deferredResultMap.get(id); | |
| 85 | - } | |
| 86 | - | |
| 87 | - public Collection<DeferredResultEx> getAllByKey(String key) { | |
| 88 | - Map<String, DeferredResultEx> deferredResultMap = map.get(key); | |
| 89 | - if (deferredResultMap == null) { | |
| 90 | - return null; | |
| 91 | - } | |
| 92 | - return deferredResultMap.values(); | |
| 93 | - } | |
| 94 | - | |
| 95 | - public boolean exist(String key, String id){ | |
| 96 | - if (key == null) { | |
| 97 | - return false; | |
| 98 | - } | |
| 99 | - Map<String, DeferredResultEx> deferredResultMap = map.get(key); | |
| 100 | - if (id == null) { | |
| 101 | - return deferredResultMap != null; | |
| 102 | - }else { | |
| 103 | - return deferredResultMap != null && deferredResultMap.get(id) != null; | |
| 104 | - } | |
| 105 | - } | |
| 106 | - | |
| 107 | - /** | |
| 108 | - * 释放单个请求 | |
| 109 | - * @param msg | |
| 110 | - */ | |
| 111 | - public void invokeResult(RequestMessage msg) { | |
| 112 | - Map<String, DeferredResultEx> deferredResultMap = map.get(msg.getKey()); | |
| 113 | - if (deferredResultMap == null) { | |
| 114 | - return; | |
| 115 | - } | |
| 116 | - DeferredResultEx result = deferredResultMap.get(msg.getId()); | |
| 117 | - if (result == null) { | |
| 118 | - return; | |
| 119 | - } | |
| 120 | - result.getDeferredResult().setResult(msg.getData()); | |
| 121 | - deferredResultMap.remove(msg.getId()); | |
| 122 | - if (deferredResultMap.size() == 0) { | |
| 123 | - map.remove(msg.getKey()); | |
| 124 | - } | |
| 125 | - } | |
| 126 | - | |
| 127 | - /** | |
| 128 | - * 释放所有的请求 | |
| 129 | - * @param msg | |
| 130 | - */ | |
| 131 | - public void invokeAllResult(RequestMessage msg) { | |
| 132 | - Map<String, DeferredResultEx> deferredResultMap = map.get(msg.getKey()); | |
| 133 | - if (deferredResultMap == null) { | |
| 134 | - return; | |
| 135 | - } | |
| 136 | - synchronized (this) { | |
| 137 | - deferredResultMap = map.get(msg.getKey()); | |
| 138 | - if (deferredResultMap == null) { | |
| 139 | - return; | |
| 140 | - } | |
| 141 | - Set<String> ids = deferredResultMap.keySet(); | |
| 142 | - for (String id : ids) { | |
| 143 | - DeferredResultEx result = deferredResultMap.get(id); | |
| 144 | - if (result == null) { | |
| 145 | - return; | |
| 146 | - } | |
| 147 | - if (result.getFilter() != null) { | |
| 148 | - Object handler = result.getFilter().handler(msg.getData()); | |
| 149 | - result.getDeferredResult().setResult(handler); | |
| 150 | - }else { | |
| 151 | - result.getDeferredResult().setResult(msg.getData()); | |
| 152 | - } | |
| 153 | - | |
| 154 | - } | |
| 155 | - map.remove(msg.getKey()); | |
| 156 | - } | |
| 157 | - } | |
| 158 | - | |
| 159 | - | |
| 160 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181.transmit.callback; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx; | |
| 4 | +import org.springframework.stereotype.Component; | |
| 5 | +import org.springframework.util.ObjectUtils; | |
| 6 | +import org.springframework.web.context.request.async.DeferredResult; | |
| 7 | + | |
| 8 | +import java.util.Collection; | |
| 9 | +import java.util.Map; | |
| 10 | +import java.util.Set; | |
| 11 | +import java.util.concurrent.ConcurrentHashMap; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * @description: 异步请求处理 | |
| 15 | + * @author: swwheihei | |
| 16 | + * @date: 2020年5月8日 下午7:59:05 | |
| 17 | + */ | |
| 18 | +@SuppressWarnings(value = {"rawtypes", "unchecked"}) | |
| 19 | +@Component | |
| 20 | +public class DeferredResultHolder { | |
| 21 | + | |
| 22 | + public static final String CALLBACK_CMD_DEVICESTATUS = "CALLBACK_DEVICESTATUS"; | |
| 23 | + | |
| 24 | + public static final String CALLBACK_CMD_DEVICEINFO = "CALLBACK_DEVICEINFO"; | |
| 25 | + | |
| 26 | + public static final String CALLBACK_CMD_DEVICECONTROL = "CALLBACK_DEVICECONTROL"; | |
| 27 | + | |
| 28 | + public static final String CALLBACK_CMD_DEVICECONFIG = "CALLBACK_DEVICECONFIG"; | |
| 29 | + | |
| 30 | + public static final String CALLBACK_CMD_CONFIGDOWNLOAD = "CALLBACK_CONFIGDOWNLOAD"; | |
| 31 | + | |
| 32 | + public static final String CALLBACK_CMD_CATALOG = "CALLBACK_CATALOG"; | |
| 33 | + | |
| 34 | + public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO"; | |
| 35 | + | |
| 36 | + public static final String CALLBACK_CMD_PLAY = "CALLBACK_PLAY"; | |
| 37 | + | |
| 38 | + public static final String CALLBACK_CMD_PLAYBACK = "CALLBACK_PLAYBACK"; | |
| 39 | + | |
| 40 | + public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD"; | |
| 41 | + | |
| 42 | + public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY"; | |
| 43 | + | |
| 44 | + public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; | |
| 45 | + | |
| 46 | + public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL"; | |
| 47 | + | |
| 48 | + public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION"; | |
| 49 | + | |
| 50 | + public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY"; | |
| 51 | + | |
| 52 | + public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM"; | |
| 53 | + | |
| 54 | + public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST"; | |
| 55 | + | |
| 56 | + public static final String CALLBACK_CMD_SNAP= "CALLBACK_SNAP"; | |
| 57 | + | |
| 58 | + private Map<String, Map<String, DeferredResultEx>> map = new ConcurrentHashMap<>(); | |
| 59 | + | |
| 60 | + | |
| 61 | + public void put(String key, String id, DeferredResultEx result) { | |
| 62 | + Map<String, DeferredResultEx> deferredResultMap = map.get(key); | |
| 63 | + if (deferredResultMap == null) { | |
| 64 | + deferredResultMap = new ConcurrentHashMap<>(); | |
| 65 | + map.put(key, deferredResultMap); | |
| 66 | + } | |
| 67 | + deferredResultMap.put(id, result); | |
| 68 | + } | |
| 69 | + | |
| 70 | + public void put(String key, String id, DeferredResult result) { | |
| 71 | + Map<String, DeferredResultEx> deferredResultMap = map.get(key); | |
| 72 | + if (deferredResultMap == null) { | |
| 73 | + deferredResultMap = new ConcurrentHashMap<>(); | |
| 74 | + map.put(key, deferredResultMap); | |
| 75 | + } | |
| 76 | + deferredResultMap.put(id, new DeferredResultEx(result)); | |
| 77 | + } | |
| 78 | + | |
| 79 | + public DeferredResultEx get(String key, String id) { | |
| 80 | + Map<String, DeferredResultEx> deferredResultMap = map.get(key); | |
| 81 | + if (deferredResultMap == null || ObjectUtils.isEmpty(id)) { | |
| 82 | + return null; | |
| 83 | + } | |
| 84 | + return deferredResultMap.get(id); | |
| 85 | + } | |
| 86 | + | |
| 87 | + public Collection<DeferredResultEx> getAllByKey(String key) { | |
| 88 | + Map<String, DeferredResultEx> deferredResultMap = map.get(key); | |
| 89 | + if (deferredResultMap == null) { | |
| 90 | + return null; | |
| 91 | + } | |
| 92 | + return deferredResultMap.values(); | |
| 93 | + } | |
| 94 | + | |
| 95 | + public boolean exist(String key, String id){ | |
| 96 | + if (key == null) { | |
| 97 | + return false; | |
| 98 | + } | |
| 99 | + Map<String, DeferredResultEx> deferredResultMap = map.get(key); | |
| 100 | + if (id == null) { | |
| 101 | + return deferredResultMap != null; | |
| 102 | + }else { | |
| 103 | + return deferredResultMap != null && deferredResultMap.get(id) != null; | |
| 104 | + } | |
| 105 | + } | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * 释放单个请求 | |
| 109 | + * @param msg | |
| 110 | + */ | |
| 111 | + public void invokeResult(RequestMessage msg) { | |
| 112 | + Map<String, DeferredResultEx> deferredResultMap = map.get(msg.getKey()); | |
| 113 | + if (deferredResultMap == null) { | |
| 114 | + return; | |
| 115 | + } | |
| 116 | + DeferredResultEx result = deferredResultMap.get(msg.getId()); | |
| 117 | + if (result == null) { | |
| 118 | + return; | |
| 119 | + } | |
| 120 | + result.getDeferredResult().setResult(msg.getData()); | |
| 121 | + deferredResultMap.remove(msg.getId()); | |
| 122 | + if (deferredResultMap.size() == 0) { | |
| 123 | + map.remove(msg.getKey()); | |
| 124 | + } | |
| 125 | + } | |
| 126 | + | |
| 127 | + /** | |
| 128 | + * 释放所有的请求 | |
| 129 | + * @param msg | |
| 130 | + */ | |
| 131 | + public void invokeAllResult(RequestMessage msg) { | |
| 132 | + Map<String, DeferredResultEx> deferredResultMap = map.get(msg.getKey()); | |
| 133 | + if (deferredResultMap == null) { | |
| 134 | + return; | |
| 135 | + } | |
| 136 | + synchronized (this) { | |
| 137 | + deferredResultMap = map.get(msg.getKey()); | |
| 138 | + if (deferredResultMap == null) { | |
| 139 | + return; | |
| 140 | + } | |
| 141 | + Set<String> ids = deferredResultMap.keySet(); | |
| 142 | + for (String id : ids) { | |
| 143 | + DeferredResultEx result = deferredResultMap.get(id); | |
| 144 | + if (result == null) { | |
| 145 | + return; | |
| 146 | + } | |
| 147 | + if (result.getFilter() != null) { | |
| 148 | + Object handler = result.getFilter().handler(msg.getData()); | |
| 149 | + result.getDeferredResult().setResult(handler); | |
| 150 | + }else { | |
| 151 | + result.getDeferredResult().setResult(msg.getData()); | |
| 152 | + } | |
| 153 | + | |
| 154 | + } | |
| 155 | + map.remove(msg.getKey()); | |
| 156 | + } | |
| 157 | + } | |
| 158 | + | |
| 159 | + | |
| 160 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.gb28181.transmit.callback; | |
| 2 | - | |
| 3 | -/** | |
| 4 | - * @description: 请求信息定义 | |
| 5 | - * @author: swwheihei | |
| 6 | - * @date: 2020年5月8日 下午1:09:18 | |
| 7 | - */ | |
| 8 | -public class RequestMessage { | |
| 9 | - | |
| 10 | - private String id; | |
| 11 | - | |
| 12 | - private String key; | |
| 13 | - | |
| 14 | - private Object data; | |
| 15 | - | |
| 16 | - public String getId() { | |
| 17 | - return id; | |
| 18 | - } | |
| 19 | - | |
| 20 | - public void setId(String id) { | |
| 21 | - this.id = id; | |
| 22 | - } | |
| 23 | - | |
| 24 | - public void setKey(String key) { | |
| 25 | - this.key = key; | |
| 26 | - } | |
| 27 | - | |
| 28 | - public String getKey() { | |
| 29 | - return key; | |
| 30 | - } | |
| 31 | - | |
| 32 | - public Object getData() { | |
| 33 | - return data; | |
| 34 | - } | |
| 35 | - | |
| 36 | - public void setData(Object data) { | |
| 37 | - this.data = data; | |
| 38 | - } | |
| 39 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181.transmit.callback; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * @description: 请求信息定义 | |
| 5 | + * @author: swwheihei | |
| 6 | + * @date: 2020年5月8日 下午1:09:18 | |
| 7 | + */ | |
| 8 | +public class RequestMessage { | |
| 9 | + | |
| 10 | + private String id; | |
| 11 | + | |
| 12 | + private String key; | |
| 13 | + | |
| 14 | + private Object data; | |
| 15 | + | |
| 16 | + public String getId() { | |
| 17 | + return id; | |
| 18 | + } | |
| 19 | + | |
| 20 | + public void setId(String id) { | |
| 21 | + this.id = id; | |
| 22 | + } | |
| 23 | + | |
| 24 | + public void setKey(String key) { | |
| 25 | + this.key = key; | |
| 26 | + } | |
| 27 | + | |
| 28 | + public String getKey() { | |
| 29 | + return key; | |
| 30 | + } | |
| 31 | + | |
| 32 | + public Object getData() { | |
| 33 | + return data; | |
| 34 | + } | |
| 35 | + | |
| 36 | + public void setData(Object data) { | |
| 37 | + this.data = data; | |
| 38 | + } | |
| 39 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.gb28181.transmit.cmd; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.common.StreamInfo; | |
| 4 | -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | |
| 5 | -import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 6 | -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; | |
| 7 | -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | |
| 8 | -import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | |
| 9 | -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 10 | -import com.genersoft.iot.vmp.service.bean.SSRCInfo; | |
| 11 | -import gov.nist.javax.sip.message.SIPRequest; | |
| 12 | - | |
| 13 | -import javax.sip.InvalidArgumentException; | |
| 14 | -import javax.sip.SipException; | |
| 15 | -import java.text.ParseException; | |
| 16 | - | |
| 17 | -/** | |
| 18 | - * @description:设备能力接口,用于定义设备的控制、查询能力 | |
| 19 | - * @author: swwheihei | |
| 20 | - * @date: 2020年5月3日 下午9:16:34 | |
| 21 | - */ | |
| 22 | -public interface ISIPCommander { | |
| 23 | - | |
| 24 | - /** | |
| 25 | - * 云台方向放控制,使用配置文件中的默认镜头移动速度 | |
| 26 | - * | |
| 27 | - * @param device 控制设备 | |
| 28 | - * @param channelId 预览通道 | |
| 29 | - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 30 | - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 31 | - */ | |
| 32 | - void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException; | |
| 33 | - | |
| 34 | - /** | |
| 35 | - * 云台方向放控制 | |
| 36 | - * | |
| 37 | - * @param device 控制设备 | |
| 38 | - * @param channelId 预览通道 | |
| 39 | - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 40 | - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 41 | - * @param moveSpeed 镜头移动速度 | |
| 42 | - */ | |
| 43 | - void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; | |
| 44 | - | |
| 45 | - /** | |
| 46 | - * 云台缩放控制,使用配置文件中的默认镜头缩放速度 | |
| 47 | - * | |
| 48 | - * @param device 控制设备 | |
| 49 | - * @param channelId 预览通道 | |
| 50 | - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 51 | - */ | |
| 52 | - void ptzZoomCmd(Device device,String channelId,int inOut) throws InvalidArgumentException, ParseException, SipException; | |
| 53 | - | |
| 54 | - /** | |
| 55 | - * 云台缩放控制 | |
| 56 | - * | |
| 57 | - * @param device 控制设备 | |
| 58 | - * @param channelId 预览通道 | |
| 59 | - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 60 | - */ | |
| 61 | - void ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; | |
| 62 | - | |
| 63 | - /** | |
| 64 | - * 云台控制,支持方向与缩放控制 | |
| 65 | - * | |
| 66 | - * @param device 控制设备 | |
| 67 | - * @param channelId 预览通道 | |
| 68 | - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 69 | - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 70 | - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 71 | - * @param moveSpeed 镜头移动速度 | |
| 72 | - * @param zoomSpeed 镜头缩放速度 | |
| 73 | - */ | |
| 74 | - void ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) throws InvalidArgumentException, SipException, ParseException; | |
| 75 | - | |
| 76 | - /** | |
| 77 | - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 | |
| 78 | - * | |
| 79 | - * @param device 控制设备 | |
| 80 | - * @param channelId 预览通道 | |
| 81 | - * @param cmdCode 指令码 | |
| 82 | - * @param parameter1 数据1 | |
| 83 | - * @param parameter2 数据2 | |
| 84 | - * @param combineCode2 组合码2 | |
| 85 | - */ | |
| 86 | - void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException; | |
| 87 | - | |
| 88 | - /** | |
| 89 | - * 前端控制指令(用于转发上级指令) | |
| 90 | - * @param device 控制设备 | |
| 91 | - * @param channelId 预览通道 | |
| 92 | - * @param cmdString 前端控制指令串 | |
| 93 | - */ | |
| 94 | - void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 95 | - | |
| 96 | - /** | |
| 97 | - * 请求预览视频流 | |
| 98 | - * @param device 视频设备 | |
| 99 | - * @param channelId 预览通道 | |
| 100 | - */ | |
| 101 | - void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 102 | - | |
| 103 | - /** | |
| 104 | - * 请求回放视频流 | |
| 105 | - * | |
| 106 | - * @param device 视频设备 | |
| 107 | - * @param channelId 预览通道 | |
| 108 | - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 109 | - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 110 | - */ | |
| 111 | - 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; | |
| 112 | - | |
| 113 | - /** | |
| 114 | - * 请求历史媒体下载 | |
| 115 | - * | |
| 116 | - * @param device 视频设备 | |
| 117 | - * @param channelId 预览通道 | |
| 118 | - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 119 | - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 120 | - * @param downloadSpeed 下载倍速参数 | |
| 121 | - */ | |
| 122 | - void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | |
| 123 | - String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent, | |
| 124 | - SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 125 | - | |
| 126 | - /** | |
| 127 | - * 视频流停止 | |
| 128 | - */ | |
| 129 | - void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; | |
| 130 | - | |
| 131 | - void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException; | |
| 132 | - | |
| 133 | - /** | |
| 134 | - * 回放暂停 | |
| 135 | - */ | |
| 136 | - void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException; | |
| 137 | - | |
| 138 | - /** | |
| 139 | - * 回放恢复 | |
| 140 | - */ | |
| 141 | - void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException; | |
| 142 | - | |
| 143 | - /** | |
| 144 | - * 回放拖动播放 | |
| 145 | - */ | |
| 146 | - void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException; | |
| 147 | - | |
| 148 | - /** | |
| 149 | - * 回放倍速播放 | |
| 150 | - */ | |
| 151 | - void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException; | |
| 152 | - | |
| 153 | - /** | |
| 154 | - * 回放控制 | |
| 155 | - * @param device | |
| 156 | - * @param streamInfo | |
| 157 | - * @param content | |
| 158 | - */ | |
| 159 | - void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException; | |
| 160 | - | |
| 161 | - | |
| 162 | - /** | |
| 163 | - * 语音广播 | |
| 164 | - * | |
| 165 | - * @param device 视频设备 | |
| 166 | - * @param channelId 预览通道 | |
| 167 | - */ | |
| 168 | - void audioBroadcastCmd(Device device,String channelId); | |
| 169 | - | |
| 170 | - /** | |
| 171 | - * 语音广播 | |
| 172 | - * | |
| 173 | - * @param device 视频设备 | |
| 174 | - */ | |
| 175 | - void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 176 | - void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException; | |
| 177 | - | |
| 178 | - /** | |
| 179 | - * 音视频录像控制 | |
| 180 | - * | |
| 181 | - * @param device 视频设备 | |
| 182 | - * @param channelId 预览通道 | |
| 183 | - * @param recordCmdStr 录像命令:Record / StopRecord | |
| 184 | - */ | |
| 185 | - void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 186 | - | |
| 187 | - /** | |
| 188 | - * 远程启动控制命令 | |
| 189 | - * | |
| 190 | - * @param device 视频设备 | |
| 191 | - */ | |
| 192 | - void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException; | |
| 193 | - | |
| 194 | - /** | |
| 195 | - * 报警布防/撤防命令 | |
| 196 | - * | |
| 197 | - * @param device 视频设备 | |
| 198 | - */ | |
| 199 | - void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 200 | - | |
| 201 | - /** | |
| 202 | - * 报警复位命令 | |
| 203 | - * | |
| 204 | - * @param device 视频设备 | |
| 205 | - * @param alarmMethod 报警方式(可选) | |
| 206 | - * @param alarmType 报警类型(可选) | |
| 207 | - */ | |
| 208 | - void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 209 | - | |
| 210 | - /** | |
| 211 | - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 | |
| 212 | - * | |
| 213 | - * @param device 视频设备 | |
| 214 | - * @param channelId 预览通道 | |
| 215 | - */ | |
| 216 | - void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException; | |
| 217 | - | |
| 218 | - /** | |
| 219 | - * 看守位控制命令 | |
| 220 | - * | |
| 221 | - * @param device 视频设备 | |
| 222 | - * @param channelId 通道id,非通道则是设备本身 | |
| 223 | - * @param enabled 看守位使能:1 = 开启,0 = 关闭 | |
| 224 | - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) | |
| 225 | - * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 | |
| 226 | - */ | |
| 227 | - void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 228 | - | |
| 229 | - /** | |
| 230 | - * 设备配置命令 | |
| 231 | - * | |
| 232 | - * @param device 视频设备 | |
| 233 | - */ | |
| 234 | - void deviceConfigCmd(Device device); | |
| 235 | - | |
| 236 | - /** | |
| 237 | - * 设备配置命令:basicParam | |
| 238 | - * | |
| 239 | - * @param device 视频设备 | |
| 240 | - * @param channelId 通道编码(可选) | |
| 241 | - * @param name 设备/通道名称(可选) | |
| 242 | - * @param expiration 注册过期时间(可选) | |
| 243 | - * @param heartBeatInterval 心跳间隔时间(可选) | |
| 244 | - * @param heartBeatCount 心跳超时次数(可选) | |
| 245 | - */ | |
| 246 | - void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 247 | - | |
| 248 | - /** | |
| 249 | - * 查询设备状态 | |
| 250 | - * | |
| 251 | - * @param device 视频设备 | |
| 252 | - */ | |
| 253 | - void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 254 | - | |
| 255 | - /** | |
| 256 | - * 查询设备信息 | |
| 257 | - * | |
| 258 | - * @param device 视频设备 | |
| 259 | - * @return | |
| 260 | - */ | |
| 261 | - void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException; | |
| 262 | - | |
| 263 | - /** | |
| 264 | - * 查询目录列表 | |
| 265 | - * | |
| 266 | - * @param device 视频设备 | |
| 267 | - */ | |
| 268 | - void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException; | |
| 269 | - | |
| 270 | - /** | |
| 271 | - * 查询录像信息 | |
| 272 | - * | |
| 273 | - * @param device 视频设备 | |
| 274 | - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 275 | - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 276 | - * @param sn | |
| 277 | - */ | |
| 278 | - 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; | |
| 279 | - | |
| 280 | - /** | |
| 281 | - * 查询报警信息 | |
| 282 | - * | |
| 283 | - * @param device 视频设备 | |
| 284 | - * @param startPriority 报警起始级别(可选) | |
| 285 | - * @param endPriority 报警终止级别(可选) | |
| 286 | - * @param alarmMethod 报警方式条件(可选) | |
| 287 | - * @param alarmType 报警类型 | |
| 288 | - * @param startTime 报警发生起始时间(可选) | |
| 289 | - * @param endTime 报警发生终止时间(可选) | |
| 290 | - * @return true = 命令发送成功 | |
| 291 | - */ | |
| 292 | - void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, | |
| 293 | - String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 294 | - | |
| 295 | - /** | |
| 296 | - * 查询设备配置 | |
| 297 | - * | |
| 298 | - * @param device 视频设备 | |
| 299 | - * @param channelId 通道编码(可选) | |
| 300 | - * @param configType 配置类型: | |
| 301 | - */ | |
| 302 | - void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 303 | - | |
| 304 | - /** | |
| 305 | - * 查询设备预置位置 | |
| 306 | - * | |
| 307 | - * @param device 视频设备 | |
| 308 | - */ | |
| 309 | - void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 310 | - | |
| 311 | - /** | |
| 312 | - * 查询移动设备位置数据 | |
| 313 | - * | |
| 314 | - * @param device 视频设备 | |
| 315 | - */ | |
| 316 | - void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 317 | - | |
| 318 | - /** | |
| 319 | - * 订阅、取消订阅移动位置 | |
| 320 | - * | |
| 321 | - * @param device 视频设备 | |
| 322 | - * @return true = 命令发送成功 | |
| 323 | - */ | |
| 324 | - SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 325 | - | |
| 326 | - /** | |
| 327 | - * 订阅、取消订阅报警信息 | |
| 328 | - * @param device 视频设备 | |
| 329 | - * @param expires 订阅过期时间(0 = 取消订阅) | |
| 330 | - * @param startPriority 报警起始级别(可选) | |
| 331 | - * @param endPriority 报警终止级别(可选) | |
| 332 | - * @param alarmType 报警类型 | |
| 333 | - * @param startTime 报警发生起始时间(可选) | |
| 334 | - * @param endTime 报警发生终止时间(可选) | |
| 335 | - * @return true = 命令发送成功 | |
| 336 | - */ | |
| 337 | - void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException; | |
| 338 | - | |
| 339 | - /** | |
| 340 | - * 订阅、取消订阅目录信息 | |
| 341 | - * @param device 视频设备 | |
| 342 | - * @return true = 命令发送成功 | |
| 343 | - */ | |
| 344 | - SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 345 | - | |
| 346 | - /** | |
| 347 | - * 拉框控制命令 | |
| 348 | - * | |
| 349 | - * @param device 控制设备 | |
| 350 | - * @param channelId 通道id | |
| 351 | - * @param cmdString 前端控制指令串 | |
| 352 | - */ | |
| 353 | - void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException; | |
| 354 | - | |
| 355 | - | |
| 356 | - /** | |
| 357 | - * 向设备发送报警NOTIFY消息, 用于互联结构下,此时将设备当成一个平级平台看待 | |
| 358 | - * @param device 设备 | |
| 359 | - * @param deviceAlarm 报警信息信息 | |
| 360 | - * @return | |
| 361 | - */ | |
| 362 | - void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException; | |
| 363 | - | |
| 364 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181.transmit.cmd; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.common.StreamInfo; | |
| 4 | +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 6 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; | |
| 7 | +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | |
| 8 | +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | |
| 9 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 10 | +import com.genersoft.iot.vmp.service.bean.SSRCInfo; | |
| 11 | +import gov.nist.javax.sip.message.SIPRequest; | |
| 12 | + | |
| 13 | +import javax.sip.InvalidArgumentException; | |
| 14 | +import javax.sip.SipException; | |
| 15 | +import java.text.ParseException; | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * @description:设备能力接口,用于定义设备的控制、查询能力 | |
| 19 | + * @author: swwheihei | |
| 20 | + * @date: 2020年5月3日 下午9:16:34 | |
| 21 | + */ | |
| 22 | +public interface ISIPCommander { | |
| 23 | + | |
| 24 | + /** | |
| 25 | + * 云台方向放控制,使用配置文件中的默认镜头移动速度 | |
| 26 | + * | |
| 27 | + * @param device 控制设备 | |
| 28 | + * @param channelId 预览通道 | |
| 29 | + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 30 | + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 31 | + */ | |
| 32 | + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException; | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 云台方向放控制 | |
| 36 | + * | |
| 37 | + * @param device 控制设备 | |
| 38 | + * @param channelId 预览通道 | |
| 39 | + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 40 | + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 41 | + * @param moveSpeed 镜头移动速度 | |
| 42 | + */ | |
| 43 | + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * 云台缩放控制,使用配置文件中的默认镜头缩放速度 | |
| 47 | + * | |
| 48 | + * @param device 控制设备 | |
| 49 | + * @param channelId 预览通道 | |
| 50 | + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 51 | + */ | |
| 52 | + void ptzZoomCmd(Device device,String channelId,int inOut) throws InvalidArgumentException, ParseException, SipException; | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * 云台缩放控制 | |
| 56 | + * | |
| 57 | + * @param device 控制设备 | |
| 58 | + * @param channelId 预览通道 | |
| 59 | + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 60 | + */ | |
| 61 | + void ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * 云台控制,支持方向与缩放控制 | |
| 65 | + * | |
| 66 | + * @param device 控制设备 | |
| 67 | + * @param channelId 预览通道 | |
| 68 | + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 69 | + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 70 | + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 71 | + * @param moveSpeed 镜头移动速度 | |
| 72 | + * @param zoomSpeed 镜头缩放速度 | |
| 73 | + */ | |
| 74 | + void ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) throws InvalidArgumentException, SipException, ParseException; | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 | |
| 78 | + * | |
| 79 | + * @param device 控制设备 | |
| 80 | + * @param channelId 预览通道 | |
| 81 | + * @param cmdCode 指令码 | |
| 82 | + * @param parameter1 数据1 | |
| 83 | + * @param parameter2 数据2 | |
| 84 | + * @param combineCode2 组合码2 | |
| 85 | + */ | |
| 86 | + void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException; | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * 前端控制指令(用于转发上级指令) | |
| 90 | + * @param device 控制设备 | |
| 91 | + * @param channelId 预览通道 | |
| 92 | + * @param cmdString 前端控制指令串 | |
| 93 | + */ | |
| 94 | + void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 95 | + | |
| 96 | + /** | |
| 97 | + * 请求预览视频流 | |
| 98 | + * @param device 视频设备 | |
| 99 | + * @param channelId 预览通道 | |
| 100 | + */ | |
| 101 | + void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * 请求回放视频流 | |
| 105 | + * | |
| 106 | + * @param device 视频设备 | |
| 107 | + * @param channelId 预览通道 | |
| 108 | + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 109 | + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 110 | + */ | |
| 111 | + 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; | |
| 112 | + | |
| 113 | + /** | |
| 114 | + * 请求历史媒体下载 | |
| 115 | + * | |
| 116 | + * @param device 视频设备 | |
| 117 | + * @param channelId 预览通道 | |
| 118 | + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 119 | + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 120 | + * @param downloadSpeed 下载倍速参数 | |
| 121 | + */ | |
| 122 | + void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | |
| 123 | + String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent, | |
| 124 | + SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 125 | + | |
| 126 | + /** | |
| 127 | + * 视频流停止 | |
| 128 | + */ | |
| 129 | + void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; | |
| 130 | + | |
| 131 | + void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException; | |
| 132 | + | |
| 133 | + /** | |
| 134 | + * 回放暂停 | |
| 135 | + */ | |
| 136 | + void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException; | |
| 137 | + | |
| 138 | + /** | |
| 139 | + * 回放恢复 | |
| 140 | + */ | |
| 141 | + void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException; | |
| 142 | + | |
| 143 | + /** | |
| 144 | + * 回放拖动播放 | |
| 145 | + */ | |
| 146 | + void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException; | |
| 147 | + | |
| 148 | + /** | |
| 149 | + * 回放倍速播放 | |
| 150 | + */ | |
| 151 | + void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException; | |
| 152 | + | |
| 153 | + /** | |
| 154 | + * 回放控制 | |
| 155 | + * @param device | |
| 156 | + * @param streamInfo | |
| 157 | + * @param content | |
| 158 | + */ | |
| 159 | + void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException; | |
| 160 | + | |
| 161 | + | |
| 162 | + /** | |
| 163 | + * 语音广播 | |
| 164 | + * | |
| 165 | + * @param device 视频设备 | |
| 166 | + * @param channelId 预览通道 | |
| 167 | + */ | |
| 168 | + void audioBroadcastCmd(Device device,String channelId); | |
| 169 | + | |
| 170 | + /** | |
| 171 | + * 语音广播 | |
| 172 | + * | |
| 173 | + * @param device 视频设备 | |
| 174 | + */ | |
| 175 | + void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 176 | + void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException; | |
| 177 | + | |
| 178 | + /** | |
| 179 | + * 音视频录像控制 | |
| 180 | + * | |
| 181 | + * @param device 视频设备 | |
| 182 | + * @param channelId 预览通道 | |
| 183 | + * @param recordCmdStr 录像命令:Record / StopRecord | |
| 184 | + */ | |
| 185 | + void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 186 | + | |
| 187 | + /** | |
| 188 | + * 远程启动控制命令 | |
| 189 | + * | |
| 190 | + * @param device 视频设备 | |
| 191 | + */ | |
| 192 | + void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException; | |
| 193 | + | |
| 194 | + /** | |
| 195 | + * 报警布防/撤防命令 | |
| 196 | + * | |
| 197 | + * @param device 视频设备 | |
| 198 | + */ | |
| 199 | + void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 200 | + | |
| 201 | + /** | |
| 202 | + * 报警复位命令 | |
| 203 | + * | |
| 204 | + * @param device 视频设备 | |
| 205 | + * @param alarmMethod 报警方式(可选) | |
| 206 | + * @param alarmType 报警类型(可选) | |
| 207 | + */ | |
| 208 | + void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 209 | + | |
| 210 | + /** | |
| 211 | + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 | |
| 212 | + * | |
| 213 | + * @param device 视频设备 | |
| 214 | + * @param channelId 预览通道 | |
| 215 | + */ | |
| 216 | + void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException; | |
| 217 | + | |
| 218 | + /** | |
| 219 | + * 看守位控制命令 | |
| 220 | + * | |
| 221 | + * @param device 视频设备 | |
| 222 | + * @param channelId 通道id,非通道则是设备本身 | |
| 223 | + * @param enabled 看守位使能:1 = 开启,0 = 关闭 | |
| 224 | + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) | |
| 225 | + * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 | |
| 226 | + */ | |
| 227 | + void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 228 | + | |
| 229 | + /** | |
| 230 | + * 设备配置命令 | |
| 231 | + * | |
| 232 | + * @param device 视频设备 | |
| 233 | + */ | |
| 234 | + void deviceConfigCmd(Device device); | |
| 235 | + | |
| 236 | + /** | |
| 237 | + * 设备配置命令:basicParam | |
| 238 | + * | |
| 239 | + * @param device 视频设备 | |
| 240 | + * @param channelId 通道编码(可选) | |
| 241 | + * @param name 设备/通道名称(可选) | |
| 242 | + * @param expiration 注册过期时间(可选) | |
| 243 | + * @param heartBeatInterval 心跳间隔时间(可选) | |
| 244 | + * @param heartBeatCount 心跳超时次数(可选) | |
| 245 | + */ | |
| 246 | + void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 247 | + | |
| 248 | + /** | |
| 249 | + * 查询设备状态 | |
| 250 | + * | |
| 251 | + * @param device 视频设备 | |
| 252 | + */ | |
| 253 | + void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 254 | + | |
| 255 | + /** | |
| 256 | + * 查询设备信息 | |
| 257 | + * | |
| 258 | + * @param device 视频设备 | |
| 259 | + * @return | |
| 260 | + */ | |
| 261 | + void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException; | |
| 262 | + | |
| 263 | + /** | |
| 264 | + * 查询目录列表 | |
| 265 | + * | |
| 266 | + * @param device 视频设备 | |
| 267 | + */ | |
| 268 | + void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException; | |
| 269 | + | |
| 270 | + /** | |
| 271 | + * 查询录像信息 | |
| 272 | + * | |
| 273 | + * @param device 视频设备 | |
| 274 | + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 275 | + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 276 | + * @param sn | |
| 277 | + */ | |
| 278 | + 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; | |
| 279 | + | |
| 280 | + /** | |
| 281 | + * 查询报警信息 | |
| 282 | + * | |
| 283 | + * @param device 视频设备 | |
| 284 | + * @param startPriority 报警起始级别(可选) | |
| 285 | + * @param endPriority 报警终止级别(可选) | |
| 286 | + * @param alarmMethod 报警方式条件(可选) | |
| 287 | + * @param alarmType 报警类型 | |
| 288 | + * @param startTime 报警发生起始时间(可选) | |
| 289 | + * @param endTime 报警发生终止时间(可选) | |
| 290 | + * @return true = 命令发送成功 | |
| 291 | + */ | |
| 292 | + void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, | |
| 293 | + String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 294 | + | |
| 295 | + /** | |
| 296 | + * 查询设备配置 | |
| 297 | + * | |
| 298 | + * @param device 视频设备 | |
| 299 | + * @param channelId 通道编码(可选) | |
| 300 | + * @param configType 配置类型: | |
| 301 | + */ | |
| 302 | + void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 303 | + | |
| 304 | + /** | |
| 305 | + * 查询设备预置位置 | |
| 306 | + * | |
| 307 | + * @param device 视频设备 | |
| 308 | + */ | |
| 309 | + void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 310 | + | |
| 311 | + /** | |
| 312 | + * 查询移动设备位置数据 | |
| 313 | + * | |
| 314 | + * @param device 视频设备 | |
| 315 | + */ | |
| 316 | + void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 317 | + | |
| 318 | + /** | |
| 319 | + * 订阅、取消订阅移动位置 | |
| 320 | + * | |
| 321 | + * @param device 视频设备 | |
| 322 | + * @return true = 命令发送成功 | |
| 323 | + */ | |
| 324 | + SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 325 | + | |
| 326 | + /** | |
| 327 | + * 订阅、取消订阅报警信息 | |
| 328 | + * @param device 视频设备 | |
| 329 | + * @param expires 订阅过期时间(0 = 取消订阅) | |
| 330 | + * @param startPriority 报警起始级别(可选) | |
| 331 | + * @param endPriority 报警终止级别(可选) | |
| 332 | + * @param alarmType 报警类型 | |
| 333 | + * @param startTime 报警发生起始时间(可选) | |
| 334 | + * @param endTime 报警发生终止时间(可选) | |
| 335 | + * @return true = 命令发送成功 | |
| 336 | + */ | |
| 337 | + void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException; | |
| 338 | + | |
| 339 | + /** | |
| 340 | + * 订阅、取消订阅目录信息 | |
| 341 | + * @param device 视频设备 | |
| 342 | + * @return true = 命令发送成功 | |
| 343 | + */ | |
| 344 | + SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | |
| 345 | + | |
| 346 | + /** | |
| 347 | + * 拉框控制命令 | |
| 348 | + * | |
| 349 | + * @param device 控制设备 | |
| 350 | + * @param channelId 通道id | |
| 351 | + * @param cmdString 前端控制指令串 | |
| 352 | + */ | |
| 353 | + void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException; | |
| 354 | + | |
| 355 | + | |
| 356 | + /** | |
| 357 | + * 向设备发送报警NOTIFY消息, 用于互联结构下,此时将设备当成一个平级平台看待 | |
| 358 | + * @param device 设备 | |
| 359 | + * @param deviceAlarm 报警信息信息 | |
| 360 | + * @return | |
| 361 | + */ | |
| 362 | + void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException; | |
| 363 | + | |
| 364 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.gb28181.transmit.cmd; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.conf.SipConfig; | |
| 4 | -import com.genersoft.iot.vmp.gb28181.SipLayer; | |
| 5 | -import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 6 | -import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; | |
| 7 | -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 8 | -import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | |
| 9 | -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 10 | -import com.genersoft.iot.vmp.utils.GitUtil; | |
| 11 | -import gov.nist.javax.sip.message.SIPRequest; | |
| 12 | -import gov.nist.javax.sip.message.SIPResponse; | |
| 13 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 14 | -import org.springframework.stereotype.Component; | |
| 15 | - | |
| 16 | -import javax.sip.InvalidArgumentException; | |
| 17 | -import javax.sip.PeerUnavailableException; | |
| 18 | -import javax.sip.SipException; | |
| 19 | -import javax.sip.SipFactory; | |
| 20 | -import javax.sip.address.Address; | |
| 21 | -import javax.sip.address.SipURI; | |
| 22 | -import javax.sip.header.*; | |
| 23 | -import javax.sip.message.Request; | |
| 24 | -import java.text.ParseException; | |
| 25 | -import java.util.ArrayList; | |
| 26 | - | |
| 27 | -/** | |
| 28 | - * @description:摄像头命令request创造器 TODO 冗余代码太多待优化 | |
| 29 | - * @author: swwheihei | |
| 30 | - * @date: 2020年5月6日 上午9:29:02 | |
| 31 | - */ | |
| 32 | -@Component | |
| 33 | -public class SIPRequestHeaderProvider { | |
| 34 | - | |
| 35 | - @Autowired | |
| 36 | - private SipConfig sipConfig; | |
| 37 | - | |
| 38 | - @Autowired | |
| 39 | - private SipLayer sipLayer; | |
| 40 | - | |
| 41 | - @Autowired | |
| 42 | - private GitUtil gitUtil; | |
| 43 | - | |
| 44 | - @Autowired | |
| 45 | - private IRedisCatchStorage redisCatchStorage; | |
| 46 | - | |
| 47 | - @Autowired | |
| 48 | - private VideoStreamSessionManager streamSession; | |
| 49 | - | |
| 50 | - public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 51 | - Request request = null; | |
| 52 | - // sipuri | |
| 53 | - SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); | |
| 54 | - // via | |
| 55 | - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 56 | - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); | |
| 57 | - viaHeader.setRPort(); | |
| 58 | - viaHeaders.add(viaHeader); | |
| 59 | - // from | |
| 60 | - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); | |
| 61 | - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 62 | - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); | |
| 63 | - // to | |
| 64 | - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); | |
| 65 | - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 66 | - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag); | |
| 67 | - | |
| 68 | - // Forwards | |
| 69 | - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 70 | - // ceq | |
| 71 | - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE); | |
| 72 | - | |
| 73 | - request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, | |
| 74 | - toHeader, viaHeaders, maxForwards); | |
| 75 | - | |
| 76 | - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 77 | - | |
| 78 | - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); | |
| 79 | - request.setContent(content, contentTypeHeader); | |
| 80 | - return request; | |
| 81 | - } | |
| 82 | - | |
| 83 | - public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 84 | - Request request = null; | |
| 85 | - //请求行 | |
| 86 | - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 87 | - //via | |
| 88 | - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 89 | - HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory(); | |
| 90 | - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); | |
| 91 | - viaHeader.setRPort(); | |
| 92 | - viaHeaders.add(viaHeader); | |
| 93 | - | |
| 94 | - //from | |
| 95 | - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); | |
| 96 | - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 97 | - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack | |
| 98 | - //to | |
| 99 | - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 100 | - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 101 | - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null); | |
| 102 | - | |
| 103 | - //Forwards | |
| 104 | - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 105 | - | |
| 106 | - //ceq | |
| 107 | - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); | |
| 108 | - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); | |
| 109 | - | |
| 110 | - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 111 | - | |
| 112 | - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); | |
| 113 | - // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort())); | |
| 114 | - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 115 | - // Subject | |
| 116 | - SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0)); | |
| 117 | - request.addHeader(subjectHeader); | |
| 118 | - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); | |
| 119 | - request.setContent(content, contentTypeHeader); | |
| 120 | - return request; | |
| 121 | - } | |
| 122 | - | |
| 123 | - public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 124 | - Request request = null; | |
| 125 | - //请求行 | |
| 126 | - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 127 | - // via | |
| 128 | - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 129 | - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); | |
| 130 | - viaHeader.setRPort(); | |
| 131 | - viaHeaders.add(viaHeader); | |
| 132 | - //from | |
| 133 | - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); | |
| 134 | - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 135 | - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack | |
| 136 | - //to | |
| 137 | - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 138 | - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 139 | - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null); | |
| 140 | - | |
| 141 | - //Forwards | |
| 142 | - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 143 | - | |
| 144 | - //ceq | |
| 145 | - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); | |
| 146 | - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); | |
| 147 | - | |
| 148 | - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); | |
| 149 | - // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort())); | |
| 150 | - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 151 | - | |
| 152 | - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 153 | - | |
| 154 | - // Subject | |
| 155 | - SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0)); | |
| 156 | - request.addHeader(subjectHeader); | |
| 157 | - | |
| 158 | - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); | |
| 159 | - request.setContent(content, contentTypeHeader); | |
| 160 | - return request; | |
| 161 | - } | |
| 162 | - | |
| 163 | - public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 164 | - Request request = null; | |
| 165 | - //请求行 | |
| 166 | - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 167 | - // via | |
| 168 | - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 169 | - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); | |
| 170 | - viaHeaders.add(viaHeader); | |
| 171 | - //from | |
| 172 | - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain()); | |
| 173 | - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 174 | - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); | |
| 175 | - //to | |
| 176 | - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress()); | |
| 177 | - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 178 | - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); | |
| 179 | - | |
| 180 | - //Forwards | |
| 181 | - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 182 | - | |
| 183 | - //ceq | |
| 184 | - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE); | |
| 185 | - CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId()); | |
| 186 | - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); | |
| 187 | - | |
| 188 | - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 189 | - | |
| 190 | - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); | |
| 191 | - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 192 | - | |
| 193 | - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 194 | - | |
| 195 | - return request; | |
| 196 | - } | |
| 197 | - | |
| 198 | - public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 199 | - Request request = null; | |
| 200 | - // sipuri | |
| 201 | - SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); | |
| 202 | - // via | |
| 203 | - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 204 | - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), | |
| 205 | - device.getTransport(), SipUtils.getNewViaTag()); | |
| 206 | - viaHeader.setRPort(); | |
| 207 | - viaHeaders.add(viaHeader); | |
| 208 | - // from | |
| 209 | - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); | |
| 210 | - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 211 | - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag()); | |
| 212 | - // to | |
| 213 | - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); | |
| 214 | - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 215 | - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, requestOld == null ? null :requestOld.getToTag()); | |
| 216 | - | |
| 217 | - // Forwards | |
| 218 | - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 219 | - | |
| 220 | - // ceq | |
| 221 | - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.SUBSCRIBE); | |
| 222 | - | |
| 223 | - request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader, | |
| 224 | - toHeader, viaHeaders, maxForwards); | |
| 225 | - | |
| 226 | - | |
| 227 | - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); | |
| 228 | - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 229 | - | |
| 230 | - // Expires | |
| 231 | - ExpiresHeader expireHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(expires); | |
| 232 | - request.addHeader(expireHeader); | |
| 233 | - | |
| 234 | - // Event | |
| 235 | - EventHeader eventHeader = SipFactory.getInstance().createHeaderFactory().createEventHeader(event); | |
| 236 | - | |
| 237 | - int random = (int) Math.floor(Math.random() * 10000); | |
| 238 | - eventHeader.setEventId(random + ""); | |
| 239 | - request.addHeader(eventHeader); | |
| 240 | - | |
| 241 | - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); | |
| 242 | - request.setContent(content, contentTypeHeader); | |
| 243 | - | |
| 244 | - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 245 | - | |
| 246 | - return request; | |
| 247 | - } | |
| 248 | - | |
| 249 | - public SIPRequest createInfoRequest(Device device, String channelId, String content, SipTransactionInfo transactionInfo) | |
| 250 | - throws SipException, ParseException, InvalidArgumentException { | |
| 251 | - if (device == null || transactionInfo == null) { | |
| 252 | - return null; | |
| 253 | - } | |
| 254 | - SIPRequest request = null; | |
| 255 | - //请求行 | |
| 256 | - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 257 | - // via | |
| 258 | - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 259 | - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); | |
| 260 | - viaHeaders.add(viaHeader); | |
| 261 | - //from | |
| 262 | - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain()); | |
| 263 | - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 264 | - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); | |
| 265 | - //to | |
| 266 | - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress()); | |
| 267 | - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 268 | - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); | |
| 269 | - | |
| 270 | - //Forwards | |
| 271 | - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 272 | - | |
| 273 | - //ceq | |
| 274 | - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO); | |
| 275 | - CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId()); | |
| 276 | - request = (SIPRequest)SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); | |
| 277 | - | |
| 278 | - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 279 | - | |
| 280 | - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); | |
| 281 | - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 282 | - | |
| 283 | - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 284 | - | |
| 285 | - if (content != null) { | |
| 286 | - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", | |
| 287 | - "MANSRTSP"); | |
| 288 | - request.setContent(content, contentTypeHeader); | |
| 289 | - } | |
| 290 | - return request; | |
| 291 | - } | |
| 292 | - | |
| 293 | - public Request createAckRequest(String localIp, SipURI sipURI, SIPResponse sipResponse) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 294 | - | |
| 295 | - | |
| 296 | - // via | |
| 297 | - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 298 | - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(localIp, sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag()); | |
| 299 | - viaHeaders.add(viaHeader); | |
| 300 | - | |
| 301 | - //Forwards | |
| 302 | - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 303 | - | |
| 304 | - //ceq | |
| 305 | - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK); | |
| 306 | - | |
| 307 | - Request request = SipFactory.getInstance().createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards); | |
| 308 | - | |
| 309 | - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 310 | - | |
| 311 | - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), localIp + ":"+sipConfig.getPort())); | |
| 312 | - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 313 | - | |
| 314 | - request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 315 | - | |
| 316 | - return request; | |
| 317 | - } | |
| 318 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181.transmit.cmd; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.conf.SipConfig; | |
| 4 | +import com.genersoft.iot.vmp.gb28181.SipLayer; | |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 6 | +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; | |
| 7 | +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | |
| 9 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 10 | +import com.genersoft.iot.vmp.utils.GitUtil; | |
| 11 | +import gov.nist.javax.sip.message.SIPRequest; | |
| 12 | +import gov.nist.javax.sip.message.SIPResponse; | |
| 13 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 14 | +import org.springframework.stereotype.Component; | |
| 15 | + | |
| 16 | +import javax.sip.InvalidArgumentException; | |
| 17 | +import javax.sip.PeerUnavailableException; | |
| 18 | +import javax.sip.SipException; | |
| 19 | +import javax.sip.SipFactory; | |
| 20 | +import javax.sip.address.Address; | |
| 21 | +import javax.sip.address.SipURI; | |
| 22 | +import javax.sip.header.*; | |
| 23 | +import javax.sip.message.Request; | |
| 24 | +import java.text.ParseException; | |
| 25 | +import java.util.ArrayList; | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * @description:摄像头命令request创造器 TODO 冗余代码太多待优化 | |
| 29 | + * @author: swwheihei | |
| 30 | + * @date: 2020年5月6日 上午9:29:02 | |
| 31 | + */ | |
| 32 | +@Component | |
| 33 | +public class SIPRequestHeaderProvider { | |
| 34 | + | |
| 35 | + @Autowired | |
| 36 | + private SipConfig sipConfig; | |
| 37 | + | |
| 38 | + @Autowired | |
| 39 | + private SipLayer sipLayer; | |
| 40 | + | |
| 41 | + @Autowired | |
| 42 | + private GitUtil gitUtil; | |
| 43 | + | |
| 44 | + @Autowired | |
| 45 | + private IRedisCatchStorage redisCatchStorage; | |
| 46 | + | |
| 47 | + @Autowired | |
| 48 | + private VideoStreamSessionManager streamSession; | |
| 49 | + | |
| 50 | + public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 51 | + Request request = null; | |
| 52 | + // sipuri | |
| 53 | + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); | |
| 54 | + // via | |
| 55 | + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 56 | + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); | |
| 57 | + viaHeader.setRPort(); | |
| 58 | + viaHeaders.add(viaHeader); | |
| 59 | + // from | |
| 60 | + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); | |
| 61 | + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 62 | + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); | |
| 63 | + // to | |
| 64 | + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); | |
| 65 | + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 66 | + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag); | |
| 67 | + | |
| 68 | + // Forwards | |
| 69 | + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 70 | + // ceq | |
| 71 | + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE); | |
| 72 | + | |
| 73 | + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, | |
| 74 | + toHeader, viaHeaders, maxForwards); | |
| 75 | + | |
| 76 | + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 77 | + | |
| 78 | + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); | |
| 79 | + request.setContent(content, contentTypeHeader); | |
| 80 | + return request; | |
| 81 | + } | |
| 82 | + | |
| 83 | + public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 84 | + Request request = null; | |
| 85 | + //请求行 | |
| 86 | + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 87 | + //via | |
| 88 | + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 89 | + HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory(); | |
| 90 | + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); | |
| 91 | + viaHeader.setRPort(); | |
| 92 | + viaHeaders.add(viaHeader); | |
| 93 | + | |
| 94 | + //from | |
| 95 | + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); | |
| 96 | + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 97 | + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack | |
| 98 | + //to | |
| 99 | + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 100 | + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 101 | + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null); | |
| 102 | + | |
| 103 | + //Forwards | |
| 104 | + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 105 | + | |
| 106 | + //ceq | |
| 107 | + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); | |
| 108 | + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); | |
| 109 | + | |
| 110 | + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 111 | + | |
| 112 | + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); | |
| 113 | + // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort())); | |
| 114 | + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 115 | + // Subject | |
| 116 | + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0)); | |
| 117 | + request.addHeader(subjectHeader); | |
| 118 | + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); | |
| 119 | + request.setContent(content, contentTypeHeader); | |
| 120 | + return request; | |
| 121 | + } | |
| 122 | + | |
| 123 | + public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 124 | + Request request = null; | |
| 125 | + //请求行 | |
| 126 | + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 127 | + // via | |
| 128 | + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 129 | + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); | |
| 130 | + viaHeader.setRPort(); | |
| 131 | + viaHeaders.add(viaHeader); | |
| 132 | + //from | |
| 133 | + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); | |
| 134 | + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 135 | + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack | |
| 136 | + //to | |
| 137 | + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 138 | + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 139 | + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null); | |
| 140 | + | |
| 141 | + //Forwards | |
| 142 | + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 143 | + | |
| 144 | + //ceq | |
| 145 | + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); | |
| 146 | + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); | |
| 147 | + | |
| 148 | + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); | |
| 149 | + // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort())); | |
| 150 | + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 151 | + | |
| 152 | + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 153 | + | |
| 154 | + // Subject | |
| 155 | + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0)); | |
| 156 | + request.addHeader(subjectHeader); | |
| 157 | + | |
| 158 | + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); | |
| 159 | + request.setContent(content, contentTypeHeader); | |
| 160 | + return request; | |
| 161 | + } | |
| 162 | + | |
| 163 | + public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 164 | + Request request = null; | |
| 165 | + //请求行 | |
| 166 | + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 167 | + // via | |
| 168 | + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 169 | + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); | |
| 170 | + viaHeaders.add(viaHeader); | |
| 171 | + //from | |
| 172 | + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain()); | |
| 173 | + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 174 | + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); | |
| 175 | + //to | |
| 176 | + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress()); | |
| 177 | + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 178 | + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); | |
| 179 | + | |
| 180 | + //Forwards | |
| 181 | + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 182 | + | |
| 183 | + //ceq | |
| 184 | + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE); | |
| 185 | + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId()); | |
| 186 | + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); | |
| 187 | + | |
| 188 | + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 189 | + | |
| 190 | + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); | |
| 191 | + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 192 | + | |
| 193 | + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 194 | + | |
| 195 | + return request; | |
| 196 | + } | |
| 197 | + | |
| 198 | + public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 199 | + Request request = null; | |
| 200 | + // sipuri | |
| 201 | + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); | |
| 202 | + // via | |
| 203 | + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 204 | + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), | |
| 205 | + device.getTransport(), SipUtils.getNewViaTag()); | |
| 206 | + viaHeader.setRPort(); | |
| 207 | + viaHeaders.add(viaHeader); | |
| 208 | + // from | |
| 209 | + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); | |
| 210 | + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 211 | + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag()); | |
| 212 | + // to | |
| 213 | + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); | |
| 214 | + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 215 | + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, requestOld == null ? null :requestOld.getToTag()); | |
| 216 | + | |
| 217 | + // Forwards | |
| 218 | + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 219 | + | |
| 220 | + // ceq | |
| 221 | + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.SUBSCRIBE); | |
| 222 | + | |
| 223 | + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader, | |
| 224 | + toHeader, viaHeaders, maxForwards); | |
| 225 | + | |
| 226 | + | |
| 227 | + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); | |
| 228 | + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 229 | + | |
| 230 | + // Expires | |
| 231 | + ExpiresHeader expireHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(expires); | |
| 232 | + request.addHeader(expireHeader); | |
| 233 | + | |
| 234 | + // Event | |
| 235 | + EventHeader eventHeader = SipFactory.getInstance().createHeaderFactory().createEventHeader(event); | |
| 236 | + | |
| 237 | + int random = (int) Math.floor(Math.random() * 10000); | |
| 238 | + eventHeader.setEventId(random + ""); | |
| 239 | + request.addHeader(eventHeader); | |
| 240 | + | |
| 241 | + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); | |
| 242 | + request.setContent(content, contentTypeHeader); | |
| 243 | + | |
| 244 | + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 245 | + | |
| 246 | + return request; | |
| 247 | + } | |
| 248 | + | |
| 249 | + public SIPRequest createInfoRequest(Device device, String channelId, String content, SipTransactionInfo transactionInfo) | |
| 250 | + throws SipException, ParseException, InvalidArgumentException { | |
| 251 | + if (device == null || transactionInfo == null) { | |
| 252 | + return null; | |
| 253 | + } | |
| 254 | + SIPRequest request = null; | |
| 255 | + //请求行 | |
| 256 | + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); | |
| 257 | + // via | |
| 258 | + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 259 | + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); | |
| 260 | + viaHeaders.add(viaHeader); | |
| 261 | + //from | |
| 262 | + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain()); | |
| 263 | + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | |
| 264 | + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); | |
| 265 | + //to | |
| 266 | + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress()); | |
| 267 | + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); | |
| 268 | + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); | |
| 269 | + | |
| 270 | + //Forwards | |
| 271 | + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 272 | + | |
| 273 | + //ceq | |
| 274 | + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO); | |
| 275 | + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId()); | |
| 276 | + request = (SIPRequest)SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); | |
| 277 | + | |
| 278 | + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 279 | + | |
| 280 | + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); | |
| 281 | + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 282 | + | |
| 283 | + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 284 | + | |
| 285 | + if (content != null) { | |
| 286 | + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", | |
| 287 | + "MANSRTSP"); | |
| 288 | + request.setContent(content, contentTypeHeader); | |
| 289 | + } | |
| 290 | + return request; | |
| 291 | + } | |
| 292 | + | |
| 293 | + public Request createAckRequest(String localIp, SipURI sipURI, SIPResponse sipResponse) throws ParseException, InvalidArgumentException, PeerUnavailableException { | |
| 294 | + | |
| 295 | + | |
| 296 | + // via | |
| 297 | + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 298 | + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(localIp, sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag()); | |
| 299 | + viaHeaders.add(viaHeader); | |
| 300 | + | |
| 301 | + //Forwards | |
| 302 | + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | |
| 303 | + | |
| 304 | + //ceq | |
| 305 | + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK); | |
| 306 | + | |
| 307 | + Request request = SipFactory.getInstance().createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards); | |
| 308 | + | |
| 309 | + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 310 | + | |
| 311 | + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), localIp + ":"+sipConfig.getPort())); | |
| 312 | + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | |
| 313 | + | |
| 314 | + request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | |
| 315 | + | |
| 316 | + return request; | |
| 317 | + } | |
| 318 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.common.InviteSessionType; | |
| 4 | -import com.genersoft.iot.vmp.common.StreamInfo; | |
| 5 | -import com.genersoft.iot.vmp.conf.SipConfig; | |
| 6 | -import com.genersoft.iot.vmp.conf.UserSetting; | |
| 7 | -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | |
| 8 | -import com.genersoft.iot.vmp.gb28181.SipLayer; | |
| 9 | -import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 10 | -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; | |
| 11 | -import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; | |
| 12 | -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | |
| 13 | -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 14 | -import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; | |
| 15 | -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; | |
| 16 | -import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; | |
| 17 | -import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; | |
| 18 | -import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | |
| 19 | -import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | |
| 20 | -import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | |
| 21 | -import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | |
| 22 | -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 23 | -import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; | |
| 24 | -import com.genersoft.iot.vmp.service.IMediaServerService; | |
| 25 | -import com.genersoft.iot.vmp.service.bean.SSRCInfo; | |
| 26 | -import com.genersoft.iot.vmp.utils.DateUtil; | |
| 27 | -import gov.nist.javax.sip.message.SIPRequest; | |
| 28 | -import gov.nist.javax.sip.message.SIPResponse; | |
| 29 | -import org.slf4j.Logger; | |
| 30 | -import org.slf4j.LoggerFactory; | |
| 31 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 32 | -import org.springframework.context.annotation.DependsOn; | |
| 33 | -import org.springframework.stereotype.Component; | |
| 34 | -import org.springframework.util.ObjectUtils; | |
| 35 | - | |
| 36 | -import javax.sip.InvalidArgumentException; | |
| 37 | -import javax.sip.ResponseEvent; | |
| 38 | -import javax.sip.SipException; | |
| 39 | -import javax.sip.SipFactory; | |
| 40 | -import javax.sip.header.CallIdHeader; | |
| 41 | -import javax.sip.message.Request; | |
| 42 | -import java.text.ParseException; | |
| 43 | - | |
| 44 | -/** | |
| 45 | - * @description:设备能力接口,用于定义设备的控制、查询能力 | |
| 46 | - * @author: swwheihei | |
| 47 | - * @date: 2020年5月3日 下午9:22:48 | |
| 48 | - */ | |
| 49 | -@Component | |
| 50 | -@DependsOn("sipLayer") | |
| 51 | -public class SIPCommander implements ISIPCommander { | |
| 52 | - | |
| 53 | - private final Logger logger = LoggerFactory.getLogger(SIPCommander.class); | |
| 54 | - | |
| 55 | - @Autowired | |
| 56 | - private SipConfig sipConfig; | |
| 57 | - | |
| 58 | - @Autowired | |
| 59 | - private SipLayer sipLayer; | |
| 60 | - | |
| 61 | - @Autowired | |
| 62 | - private SIPSender sipSender; | |
| 63 | - | |
| 64 | - @Autowired | |
| 65 | - private SIPRequestHeaderProvider headerProvider; | |
| 66 | - | |
| 67 | - @Autowired | |
| 68 | - private VideoStreamSessionManager streamSession; | |
| 69 | - | |
| 70 | - @Autowired | |
| 71 | - private UserSetting userSetting; | |
| 72 | - | |
| 73 | - @Autowired | |
| 74 | - private ZlmHttpHookSubscribe subscribe; | |
| 75 | - | |
| 76 | - | |
| 77 | - | |
| 78 | - @Autowired | |
| 79 | - private IMediaServerService mediaServerService; | |
| 80 | - | |
| 81 | - | |
| 82 | - /** | |
| 83 | - * 云台方向放控制,使用配置文件中的默认镜头移动速度 | |
| 84 | - * | |
| 85 | - * @param device 控制设备 | |
| 86 | - * @param channelId 预览通道 | |
| 87 | - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 88 | - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 89 | - */ | |
| 90 | - @Override | |
| 91 | - public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException { | |
| 92 | - ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0); | |
| 93 | - } | |
| 94 | - | |
| 95 | - /** | |
| 96 | - * 云台方向放控制 | |
| 97 | - * | |
| 98 | - * @param device 控制设备 | |
| 99 | - * @param channelId 预览通道 | |
| 100 | - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 101 | - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 102 | - * @param moveSpeed 镜头移动速度 | |
| 103 | - */ | |
| 104 | - @Override | |
| 105 | - public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException { | |
| 106 | - ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0); | |
| 107 | - } | |
| 108 | - | |
| 109 | - /** | |
| 110 | - * 云台缩放控制,使用配置文件中的默认镜头缩放速度 | |
| 111 | - * | |
| 112 | - * @param device 控制设备 | |
| 113 | - * @param channelId 预览通道 | |
| 114 | - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 115 | - */ | |
| 116 | - @Override | |
| 117 | - public void ptzZoomCmd(Device device, String channelId, int inOut) throws InvalidArgumentException, ParseException, SipException { | |
| 118 | - ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed()); | |
| 119 | - } | |
| 120 | - | |
| 121 | - /** | |
| 122 | - * 云台缩放控制 | |
| 123 | - * | |
| 124 | - * @param device 控制设备 | |
| 125 | - * @param channelId 预览通道 | |
| 126 | - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 127 | - * @param zoomSpeed 镜头缩放速度 | |
| 128 | - */ | |
| 129 | - @Override | |
| 130 | - public void ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) throws InvalidArgumentException, ParseException, SipException { | |
| 131 | - ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed); | |
| 132 | - } | |
| 133 | - | |
| 134 | - /** | |
| 135 | - * 云台指令码计算 | |
| 136 | - * | |
| 137 | - * @param cmdCode 指令码 | |
| 138 | - * @param parameter1 数据1 | |
| 139 | - * @param parameter2 数据2 | |
| 140 | - * @param combineCode2 组合码2 | |
| 141 | - */ | |
| 142 | - public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) { | |
| 143 | - StringBuilder builder = new StringBuilder("A50F01"); | |
| 144 | - String strTmp; | |
| 145 | - strTmp = String.format("%02X", cmdCode); | |
| 146 | - builder.append(strTmp, 0, 2); | |
| 147 | - strTmp = String.format("%02X", parameter1); | |
| 148 | - builder.append(strTmp, 0, 2); | |
| 149 | - strTmp = String.format("%02X", parameter2); | |
| 150 | - builder.append(strTmp, 0, 2); | |
| 151 | - //优化zoom变倍速率 | |
| 152 | - if ((combineCode2 > 0) && (combineCode2 <16)) | |
| 153 | - { | |
| 154 | - combineCode2 = 16; | |
| 155 | - } | |
| 156 | - strTmp = String.format("%X", combineCode2); | |
| 157 | - builder.append(strTmp, 0, 1).append("0"); | |
| 158 | - //计算校验码 | |
| 159 | - int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100; | |
| 160 | - strTmp = String.format("%02X", checkCode); | |
| 161 | - builder.append(strTmp, 0, 2); | |
| 162 | - return builder.toString(); | |
| 163 | - } | |
| 164 | - | |
| 165 | - /** | |
| 166 | - * 云台控制,支持方向与缩放控制 | |
| 167 | - * | |
| 168 | - * @param device 控制设备 | |
| 169 | - * @param channelId 预览通道 | |
| 170 | - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 171 | - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 172 | - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 173 | - * @param moveSpeed 镜头移动速度 | |
| 174 | - * @param zoomSpeed 镜头缩放速度 | |
| 175 | - */ | |
| 176 | - @Override | |
| 177 | - public void ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed, | |
| 178 | - int zoomSpeed) throws InvalidArgumentException, SipException, ParseException { | |
| 179 | - String cmdStr = SipUtils.cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed); | |
| 180 | - StringBuilder ptzXml = new StringBuilder(200); | |
| 181 | - String charset = device.getCharset(); | |
| 182 | - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 183 | - ptzXml.append("<Control>\r\n"); | |
| 184 | - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 185 | - ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 186 | - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 187 | - ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n"); | |
| 188 | - ptzXml.append("<Info>\r\n"); | |
| 189 | - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n"); | |
| 190 | - ptzXml.append("</Info>\r\n"); | |
| 191 | - ptzXml.append("</Control>\r\n"); | |
| 192 | - | |
| 193 | - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 194 | - | |
| 195 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); | |
| 196 | - } | |
| 197 | - | |
| 198 | - /** | |
| 199 | - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 | |
| 200 | - * | |
| 201 | - * @param device 控制设备 | |
| 202 | - * @param channelId 预览通道 | |
| 203 | - * @param cmdCode 指令码 | |
| 204 | - * @param parameter1 数据1 | |
| 205 | - * @param parameter2 数据2 | |
| 206 | - * @param combineCode2 组合码2 | |
| 207 | - */ | |
| 208 | - @Override | |
| 209 | - public void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException { | |
| 210 | - | |
| 211 | - String cmdStr = frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2); | |
| 212 | - StringBuffer ptzXml = new StringBuffer(200); | |
| 213 | - String charset = device.getCharset(); | |
| 214 | - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 215 | - ptzXml.append("<Control>\r\n"); | |
| 216 | - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 217 | - ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 218 | - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 219 | - ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n"); | |
| 220 | - ptzXml.append("<Info>\r\n"); | |
| 221 | - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n"); | |
| 222 | - ptzXml.append("</Info>\r\n"); | |
| 223 | - ptzXml.append("</Control>\r\n"); | |
| 224 | - | |
| 225 | - | |
| 226 | - | |
| 227 | - | |
| 228 | - SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 229 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); | |
| 230 | - | |
| 231 | - } | |
| 232 | - | |
| 233 | - /** | |
| 234 | - * 前端控制指令(用于转发上级指令) | |
| 235 | - * | |
| 236 | - * @param device 控制设备 | |
| 237 | - * @param channelId 预览通道 | |
| 238 | - * @param cmdString 前端控制指令串 | |
| 239 | - */ | |
| 240 | - @Override | |
| 241 | - public void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 242 | - | |
| 243 | - StringBuffer ptzXml = new StringBuffer(200); | |
| 244 | - String charset = device.getCharset(); | |
| 245 | - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 246 | - ptzXml.append("<Control>\r\n"); | |
| 247 | - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 248 | - ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 249 | - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 250 | - ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n"); | |
| 251 | - ptzXml.append("<Info>\r\n"); | |
| 252 | - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n"); | |
| 253 | - ptzXml.append("</Info>\r\n"); | |
| 254 | - ptzXml.append("</Control>\r\n"); | |
| 255 | - | |
| 256 | - | |
| 257 | - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 258 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request, errorEvent, okEvent); | |
| 259 | - | |
| 260 | - } | |
| 261 | - | |
| 262 | - /** | |
| 263 | - * 请求预览视频流 | |
| 264 | - * | |
| 265 | - * @param device 视频设备 | |
| 266 | - * @param channelId 预览通道 | |
| 267 | - * @param event hook订阅 | |
| 268 | - * @param errorEvent sip错误订阅 | |
| 269 | - */ | |
| 270 | - @Override | |
| 271 | - public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | |
| 272 | - ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 273 | - String stream = ssrcInfo.getStream(); | |
| 274 | - | |
| 275 | - if (device == null) { | |
| 276 | - return; | |
| 277 | - } | |
| 278 | - | |
| 279 | - logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); | |
| 280 | - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); | |
| 281 | - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> { | |
| 282 | - if (event != null) { | |
| 283 | - event.response(mediaServerItemInUse, hookParam); | |
| 284 | - subscribe.removeSubscribe(hookSubscribe); | |
| 285 | - } | |
| 286 | - }); | |
| 287 | - String sdpIp; | |
| 288 | - if (!ObjectUtils.isEmpty(device.getSdpIp())) { | |
| 289 | - sdpIp = device.getSdpIp(); | |
| 290 | - }else { | |
| 291 | - sdpIp = mediaServerItem.getSdpIp(); | |
| 292 | - } | |
| 293 | - StringBuffer content = new StringBuffer(200); | |
| 294 | - content.append("v=0\r\n"); | |
| 295 | - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); | |
| 296 | - content.append("s=Play\r\n"); | |
| 297 | - content.append("c=IN IP4 " + sdpIp + "\r\n"); | |
| 298 | - content.append("t=0 0\r\n"); | |
| 299 | - | |
| 300 | - if (userSetting.isSeniorSdp()) { | |
| 301 | - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { | |
| 302 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 303 | - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { | |
| 304 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 305 | - } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) { | |
| 306 | - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 307 | - } | |
| 308 | - content.append("a=recvonly\r\n"); | |
| 309 | - content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 310 | - content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); | |
| 311 | - content.append("a=rtpmap:126 H264/90000\r\n"); | |
| 312 | - content.append("a=rtpmap:125 H264S/90000\r\n"); | |
| 313 | - content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); | |
| 314 | - content.append("a=rtpmap:99 H265/90000\r\n"); | |
| 315 | - content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 316 | - content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 317 | - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式 | |
| 318 | - content.append("a=setup:passive\r\n"); | |
| 319 | - content.append("a=connection:new\r\n"); | |
| 320 | - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 | |
| 321 | - content.append("a=setup:active\r\n"); | |
| 322 | - content.append("a=connection:new\r\n"); | |
| 323 | - } | |
| 324 | - } else { | |
| 325 | - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { | |
| 326 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 327 | - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { | |
| 328 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 329 | - } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) { | |
| 330 | - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); | |
| 331 | - } | |
| 332 | - content.append("a=recvonly\r\n"); | |
| 333 | - content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 334 | - content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 335 | - content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 336 | - content.append("a=rtpmap:99 H265/90000\r\n"); | |
| 337 | - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式 | |
| 338 | - content.append("a=setup:passive\r\n"); | |
| 339 | - content.append("a=connection:new\r\n"); | |
| 340 | - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 | |
| 341 | - content.append("a=setup:active\r\n"); | |
| 342 | - content.append("a=connection:new\r\n"); | |
| 343 | - } | |
| 344 | - } | |
| 345 | - | |
| 346 | - if( device.isSwitchPrimarySubStream() ){ | |
| 347 | - if("TP-LINK".equals(device.getManufacturer())){ | |
| 348 | - if (device.isSwitchPrimarySubStream()){ | |
| 349 | - content.append("a=streamMode:sub\r\n"); | |
| 350 | - }else { | |
| 351 | - content.append("a=streamMode:main\r\n"); | |
| 352 | - } | |
| 353 | - }else { | |
| 354 | - if (device.isSwitchPrimarySubStream()){ | |
| 355 | - content.append("a=streamprofile:1\r\n"); | |
| 356 | - }else { | |
| 357 | - content.append("a=streamprofile:0\r\n"); | |
| 358 | - } | |
| 359 | - } | |
| 360 | - } | |
| 361 | - | |
| 362 | - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc | |
| 363 | - // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率 | |
| 364 | -// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备 | |
| 365 | - | |
| 366 | - | |
| 367 | - | |
| 368 | - Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 369 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> { | |
| 370 | - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 371 | - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 372 | - errorEvent.response(e); | |
| 373 | - }), e -> { | |
| 374 | - ResponseEvent responseEvent = (ResponseEvent) e.event; | |
| 375 | - SIPResponse response = (SIPResponse) responseEvent.getResponse(); | |
| 376 | - streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, | |
| 377 | - InviteSessionType.PLAY); | |
| 378 | - okEvent.response(e); | |
| 379 | - }); | |
| 380 | - } | |
| 381 | - | |
| 382 | - /** | |
| 383 | - * 请求回放视频流 | |
| 384 | - * | |
| 385 | - * @param device 视频设备 | |
| 386 | - * @param channelId 预览通道 | |
| 387 | - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 388 | - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 389 | - */ | |
| 390 | - @Override | |
| 391 | - public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | |
| 392 | - String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent, | |
| 393 | - SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 394 | - | |
| 395 | - | |
| 396 | - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); | |
| 397 | - String sdpIp; | |
| 398 | - if (!ObjectUtils.isEmpty(device.getSdpIp())) { | |
| 399 | - sdpIp = device.getSdpIp(); | |
| 400 | - }else { | |
| 401 | - sdpIp = mediaServerItem.getSdpIp(); | |
| 402 | - } | |
| 403 | - StringBuffer content = new StringBuffer(200); | |
| 404 | - content.append("v=0\r\n"); | |
| 405 | - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); | |
| 406 | - content.append("s=Playback\r\n"); | |
| 407 | - content.append("u=" + channelId + ":0\r\n"); | |
| 408 | - content.append("c=IN IP4 " + sdpIp + "\r\n"); | |
| 409 | - content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " " | |
| 410 | - + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n"); | |
| 411 | - | |
| 412 | - String streamMode = device.getStreamMode(); | |
| 413 | - | |
| 414 | - if (userSetting.isSeniorSdp()) { | |
| 415 | - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { | |
| 416 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 417 | - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { | |
| 418 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 419 | - } else if ("UDP".equalsIgnoreCase(streamMode)) { | |
| 420 | - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 421 | - } | |
| 422 | - content.append("a=recvonly\r\n"); | |
| 423 | - content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 424 | - content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); | |
| 425 | - content.append("a=rtpmap:126 H264/90000\r\n"); | |
| 426 | - content.append("a=rtpmap:125 H264S/90000\r\n"); | |
| 427 | - content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); | |
| 428 | - content.append("a=rtpmap:99 H265/90000\r\n"); | |
| 429 | - content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 430 | - content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 431 | - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式 | |
| 432 | - content.append("a=setup:passive\r\n"); | |
| 433 | - content.append("a=connection:new\r\n"); | |
| 434 | - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式 | |
| 435 | - content.append("a=setup:active\r\n"); | |
| 436 | - content.append("a=connection:new\r\n"); | |
| 437 | - } | |
| 438 | - } else { | |
| 439 | - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { | |
| 440 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 441 | - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { | |
| 442 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 443 | - } else if ("UDP".equalsIgnoreCase(streamMode)) { | |
| 444 | - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); | |
| 445 | - } | |
| 446 | - content.append("a=recvonly\r\n"); | |
| 447 | - content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 448 | - content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 449 | - content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 450 | - content.append("a=rtpmap:99 H265/90000\r\n"); | |
| 451 | - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { | |
| 452 | - // tcp被动模式 | |
| 453 | - content.append("a=setup:passive\r\n"); | |
| 454 | - content.append("a=connection:new\r\n"); | |
| 455 | - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { | |
| 456 | - // tcp主动模式 | |
| 457 | - content.append("a=setup:active\r\n"); | |
| 458 | - content.append("a=connection:new\r\n"); | |
| 459 | - } | |
| 460 | - } | |
| 461 | - | |
| 462 | - //ssrc | |
| 463 | - content.append("y=" + ssrcInfo.getSsrc() + "\r\n"); | |
| 464 | - | |
| 465 | - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); | |
| 466 | - // 添加订阅 | |
| 467 | - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> { | |
| 468 | - if (hookEvent != null) { | |
| 469 | - hookEvent.response(mediaServerItemInUse, hookParam); | |
| 470 | - } | |
| 471 | - subscribe.removeSubscribe(hookSubscribe); | |
| 472 | - }); | |
| 473 | - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc()); | |
| 474 | - | |
| 475 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { | |
| 476 | - ResponseEvent responseEvent = (ResponseEvent) event.event; | |
| 477 | - SIPResponse response = (SIPResponse) responseEvent.getResponse(); | |
| 478 | - streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK); | |
| 479 | - okEvent.response(event); | |
| 480 | - }); | |
| 481 | - } | |
| 482 | - | |
| 483 | - /** | |
| 484 | - * 请求历史媒体下载 | |
| 485 | - * | |
| 486 | - * @param device 视频设备 | |
| 487 | - * @param channelId 预览通道 | |
| 488 | - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 489 | - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 490 | - * @param downloadSpeed 下载倍速参数 | |
| 491 | - */ | |
| 492 | - @Override | |
| 493 | - public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | |
| 494 | - String startTime, String endTime, int downloadSpeed, | |
| 495 | - ZlmHttpHookSubscribe.Event hookEvent, | |
| 496 | - SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 497 | - | |
| 498 | - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); | |
| 499 | - String sdpIp; | |
| 500 | - if (!ObjectUtils.isEmpty(device.getSdpIp())) { | |
| 501 | - sdpIp = device.getSdpIp(); | |
| 502 | - }else { | |
| 503 | - sdpIp = mediaServerItem.getSdpIp(); | |
| 504 | - } | |
| 505 | - StringBuffer content = new StringBuffer(200); | |
| 506 | - content.append("v=0\r\n"); | |
| 507 | - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); | |
| 508 | - content.append("s=Download\r\n"); | |
| 509 | - content.append("u=" + channelId + ":0\r\n"); | |
| 510 | - content.append("c=IN IP4 " + sdpIp + "\r\n"); | |
| 511 | - content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " " | |
| 512 | - + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n"); | |
| 513 | - | |
| 514 | - String streamMode = device.getStreamMode().toUpperCase(); | |
| 515 | - | |
| 516 | - if (userSetting.isSeniorSdp()) { | |
| 517 | - if ("TCP-PASSIVE".equals(streamMode)) { | |
| 518 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 519 | - } else if ("TCP-ACTIVE".equals(streamMode)) { | |
| 520 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 521 | - } else if ("UDP".equals(streamMode)) { | |
| 522 | - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 523 | - } | |
| 524 | - content.append("a=recvonly\r\n"); | |
| 525 | - content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 526 | - content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); | |
| 527 | - content.append("a=rtpmap:126 H264/90000\r\n"); | |
| 528 | - content.append("a=rtpmap:125 H264S/90000\r\n"); | |
| 529 | - content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); | |
| 530 | - content.append("a=rtpmap:99 MP4V-ES/90000\r\n"); | |
| 531 | - content.append("a=fmtp:99 profile-level-id=3\r\n"); | |
| 532 | - content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 533 | - content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 534 | - if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 | |
| 535 | - content.append("a=setup:passive\r\n"); | |
| 536 | - content.append("a=connection:new\r\n"); | |
| 537 | - } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 | |
| 538 | - content.append("a=setup:active\r\n"); | |
| 539 | - content.append("a=connection:new\r\n"); | |
| 540 | - } | |
| 541 | - } else { | |
| 542 | - if ("TCP-PASSIVE".equals(streamMode)) { | |
| 543 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 544 | - } else if ("TCP-ACTIVE".equals(streamMode)) { | |
| 545 | - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 546 | - } else if ("UDP".equals(streamMode)) { | |
| 547 | - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); | |
| 548 | - } | |
| 549 | - content.append("a=recvonly\r\n"); | |
| 550 | - content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 551 | - content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 552 | - content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 553 | - content.append("a=rtpmap:99 H265/90000\r\n"); | |
| 554 | - if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 | |
| 555 | - content.append("a=setup:passive\r\n"); | |
| 556 | - content.append("a=connection:new\r\n"); | |
| 557 | - } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 | |
| 558 | - content.append("a=setup:active\r\n"); | |
| 559 | - content.append("a=connection:new\r\n"); | |
| 560 | - } | |
| 561 | - } | |
| 562 | - content.append("a=downloadspeed:" + downloadSpeed + "\r\n"); | |
| 563 | - | |
| 564 | - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc | |
| 565 | - logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc()); | |
| 566 | - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); | |
| 567 | - // 添加订阅 | |
| 568 | - CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); | |
| 569 | - String callId= newCallIdHeader.getCallId(); | |
| 570 | - subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> { | |
| 571 | - logger.debug("sipc 添加订阅===callId {}",callId); | |
| 572 | - hookEvent.response(mediaServerItemInUse, hookParam); | |
| 573 | - subscribe.removeSubscribe(hookSubscribe); | |
| 574 | - hookSubscribe.getContent().put("regist", false); | |
| 575 | - hookSubscribe.getContent().put("schema", "rtsp"); | |
| 576 | - // 添加流注销的订阅,注销了后向设备发送bye | |
| 577 | - subscribe.addSubscribe(hookSubscribe, | |
| 578 | - (mediaServerItemForEnd, hookParam1) -> { | |
| 579 | - logger.info("[录像]下载结束, 发送BYE"); | |
| 580 | - try { | |
| 581 | - streamByeCmd(device, channelId, ssrcInfo.getStream(), callId); | |
| 582 | - } catch (InvalidArgumentException | ParseException | SipException | | |
| 583 | - SsrcTransactionNotFoundException e) { | |
| 584 | - logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage()); | |
| 585 | - } | |
| 586 | - }); | |
| 587 | - }); | |
| 588 | - | |
| 589 | - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc()); | |
| 590 | - | |
| 591 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { | |
| 592 | - ResponseEvent responseEvent = (ResponseEvent) event.event; | |
| 593 | - SIPResponse response = (SIPResponse) responseEvent.getResponse(); | |
| 594 | - String contentString =new String(response.getRawContent()); | |
| 595 | - String ssrc = SipUtils.getSsrcFromSdp(contentString); | |
| 596 | - streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD); | |
| 597 | - okEvent.response(event); | |
| 598 | - }); | |
| 599 | - } | |
| 600 | - | |
| 601 | - /** | |
| 602 | - * 视频流停止, 不使用回调 | |
| 603 | - */ | |
| 604 | - @Override | |
| 605 | - public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException { | |
| 606 | - streamByeCmd(device, channelId, stream, callId, null); | |
| 607 | - } | |
| 608 | - | |
| 609 | - /** | |
| 610 | - * 视频流停止 | |
| 611 | - */ | |
| 612 | - @Override | |
| 613 | - public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { | |
| 614 | - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callId, stream); | |
| 615 | - if (ssrcTransaction == null) { | |
| 616 | - throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream); | |
| 617 | - } | |
| 618 | - | |
| 619 | - mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); | |
| 620 | - mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); | |
| 621 | - streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); | |
| 622 | - | |
| 623 | - Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo()); | |
| 624 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent); | |
| 625 | - } | |
| 626 | - | |
| 627 | - /** | |
| 628 | - * 语音广播 | |
| 629 | - * | |
| 630 | - * @param device 视频设备 | |
| 631 | - * @param channelId 预览通道 | |
| 632 | - */ | |
| 633 | - @Override | |
| 634 | - public void audioBroadcastCmd(Device device, String channelId) { | |
| 635 | - } | |
| 636 | - | |
| 637 | - /** | |
| 638 | - * 语音广播 | |
| 639 | - * | |
| 640 | - * @param device 视频设备 | |
| 641 | - */ | |
| 642 | - @Override | |
| 643 | - public void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException { | |
| 644 | - | |
| 645 | - StringBuffer broadcastXml = new StringBuffer(200); | |
| 646 | - String charset = device.getCharset(); | |
| 647 | - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 648 | - broadcastXml.append("<Notify>\r\n"); | |
| 649 | - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n"); | |
| 650 | - broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 651 | - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n"); | |
| 652 | - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n"); | |
| 653 | - broadcastXml.append("</Notify>\r\n"); | |
| 654 | - | |
| 655 | - | |
| 656 | - | |
| 657 | - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 658 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); | |
| 659 | - | |
| 660 | - } | |
| 661 | - | |
| 662 | - @Override | |
| 663 | - public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 664 | - | |
| 665 | - StringBuffer broadcastXml = new StringBuffer(200); | |
| 666 | - String charset = device.getCharset(); | |
| 667 | - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 668 | - broadcastXml.append("<Notify>\r\n"); | |
| 669 | - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n"); | |
| 670 | - broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 671 | - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n"); | |
| 672 | - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n"); | |
| 673 | - broadcastXml.append("</Notify>\r\n"); | |
| 674 | - | |
| 675 | - | |
| 676 | - | |
| 677 | - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 678 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 679 | - | |
| 680 | - } | |
| 681 | - | |
| 682 | - | |
| 683 | - /** | |
| 684 | - * 音视频录像控制 | |
| 685 | - * | |
| 686 | - * @param device 视频设备 | |
| 687 | - * @param channelId 预览通道 | |
| 688 | - * @param recordCmdStr 录像命令:Record / StopRecord | |
| 689 | - */ | |
| 690 | - @Override | |
| 691 | - public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 692 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 693 | - String charset = device.getCharset(); | |
| 694 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 695 | - cmdXml.append("<Control>\r\n"); | |
| 696 | - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 697 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 698 | - if (ObjectUtils.isEmpty(channelId)) { | |
| 699 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 700 | - } else { | |
| 701 | - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 702 | - } | |
| 703 | - cmdXml.append("<RecordCmd>" + recordCmdStr + "</RecordCmd>\r\n"); | |
| 704 | - cmdXml.append("</Control>\r\n"); | |
| 705 | - | |
| 706 | - | |
| 707 | - | |
| 708 | - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 709 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); | |
| 710 | - } | |
| 711 | - | |
| 712 | - /** | |
| 713 | - * 远程启动控制命令 | |
| 714 | - * | |
| 715 | - * @param device 视频设备 | |
| 716 | - */ | |
| 717 | - @Override | |
| 718 | - public void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException { | |
| 719 | - | |
| 720 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 721 | - String charset = device.getCharset(); | |
| 722 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 723 | - cmdXml.append("<Control>\r\n"); | |
| 724 | - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 725 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 726 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 727 | - cmdXml.append("<TeleBoot>Boot</TeleBoot>\r\n"); | |
| 728 | - cmdXml.append("</Control>\r\n"); | |
| 729 | - | |
| 730 | - | |
| 731 | - | |
| 732 | - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 733 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); | |
| 734 | - } | |
| 735 | - | |
| 736 | - /** | |
| 737 | - * 报警布防/撤防命令 | |
| 738 | - * | |
| 739 | - * @param device 视频设备 | |
| 740 | - * @param guardCmdStr "SetGuard"/"ResetGuard" | |
| 741 | - */ | |
| 742 | - @Override | |
| 743 | - public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 744 | - | |
| 745 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 746 | - String charset = device.getCharset(); | |
| 747 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 748 | - cmdXml.append("<Control>\r\n"); | |
| 749 | - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 750 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 751 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 752 | - cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n"); | |
| 753 | - cmdXml.append("</Control>\r\n"); | |
| 754 | - | |
| 755 | - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 756 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); | |
| 757 | - } | |
| 758 | - | |
| 759 | - /** | |
| 760 | - * 报警复位命令 | |
| 761 | - * | |
| 762 | - * @param device 视频设备 | |
| 763 | - */ | |
| 764 | - @Override | |
| 765 | - public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 766 | - | |
| 767 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 768 | - String charset = device.getCharset(); | |
| 769 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 770 | - cmdXml.append("<Control>\r\n"); | |
| 771 | - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 772 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 773 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 774 | - cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n"); | |
| 775 | - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { | |
| 776 | - cmdXml.append("<Info>\r\n"); | |
| 777 | - } | |
| 778 | - if (!ObjectUtils.isEmpty(alarmMethod)) { | |
| 779 | - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n"); | |
| 780 | - } | |
| 781 | - if (!ObjectUtils.isEmpty(alarmType)) { | |
| 782 | - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n"); | |
| 783 | - } | |
| 784 | - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { | |
| 785 | - cmdXml.append("</Info>\r\n"); | |
| 786 | - } | |
| 787 | - cmdXml.append("</Control>\r\n"); | |
| 788 | - | |
| 789 | - | |
| 790 | - | |
| 791 | - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 792 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); | |
| 793 | - } | |
| 794 | - | |
| 795 | - /** | |
| 796 | - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 | |
| 797 | - * | |
| 798 | - * @param device 视频设备 | |
| 799 | - * @param channelId 预览通道 | |
| 800 | - */ | |
| 801 | - @Override | |
| 802 | - public void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException { | |
| 803 | - | |
| 804 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 805 | - String charset = device.getCharset(); | |
| 806 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 807 | - cmdXml.append("<Control>\r\n"); | |
| 808 | - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 809 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 810 | - if (ObjectUtils.isEmpty(channelId)) { | |
| 811 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 812 | - } else { | |
| 813 | - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 814 | - } | |
| 815 | - cmdXml.append("<IFameCmd>Send</IFameCmd>\r\n"); | |
| 816 | - cmdXml.append("</Control>\r\n"); | |
| 817 | - | |
| 818 | - | |
| 819 | - | |
| 820 | - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 821 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); | |
| 822 | - } | |
| 823 | - | |
| 824 | - /** | |
| 825 | - * 看守位控制命令 | |
| 826 | - * | |
| 827 | - * @param device 视频设备 | |
| 828 | - * @param channelId 通道id,非通道则是设备本身 | |
| 829 | - * @param enabled 看守位使能:1 = 开启,0 = 关闭 | |
| 830 | - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) | |
| 831 | - * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 | |
| 832 | - */ | |
| 833 | - @Override | |
| 834 | - public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 835 | - | |
| 836 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 837 | - String charset = device.getCharset(); | |
| 838 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 839 | - cmdXml.append("<Control>\r\n"); | |
| 840 | - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 841 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 842 | - if (ObjectUtils.isEmpty(channelId)) { | |
| 843 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 844 | - } else { | |
| 845 | - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 846 | - } | |
| 847 | - cmdXml.append("<HomePosition>\r\n"); | |
| 848 | - if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) { | |
| 849 | - cmdXml.append("<Enabled>1</Enabled>\r\n"); | |
| 850 | - if (NumericUtil.isInteger(resetTime)) { | |
| 851 | - cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n"); | |
| 852 | - } else { | |
| 853 | - cmdXml.append("<ResetTime>0</ResetTime>\r\n"); | |
| 854 | - } | |
| 855 | - if (NumericUtil.isInteger(presetIndex)) { | |
| 856 | - cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n"); | |
| 857 | - } else { | |
| 858 | - cmdXml.append("<PresetIndex>0</PresetIndex>\r\n"); | |
| 859 | - } | |
| 860 | - } else { | |
| 861 | - cmdXml.append("<Enabled>0</Enabled>\r\n"); | |
| 862 | - } | |
| 863 | - cmdXml.append("</HomePosition>\r\n"); | |
| 864 | - cmdXml.append("</Control>\r\n"); | |
| 865 | - | |
| 866 | - | |
| 867 | - | |
| 868 | - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 869 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); | |
| 870 | - } | |
| 871 | - | |
| 872 | - /** | |
| 873 | - * 设备配置命令 | |
| 874 | - * | |
| 875 | - * @param device 视频设备 | |
| 876 | - */ | |
| 877 | - @Override | |
| 878 | - public void deviceConfigCmd(Device device) { | |
| 879 | - // TODO Auto-generated method stub | |
| 880 | - } | |
| 881 | - | |
| 882 | - /** | |
| 883 | - * 设备配置命令:basicParam | |
| 884 | - * | |
| 885 | - * @param device 视频设备 | |
| 886 | - * @param channelId 通道编码(可选) | |
| 887 | - * @param name 设备/通道名称(可选) | |
| 888 | - * @param expiration 注册过期时间(可选) | |
| 889 | - * @param heartBeatInterval 心跳间隔时间(可选) | |
| 890 | - * @param heartBeatCount 心跳超时次数(可选) | |
| 891 | - */ | |
| 892 | - @Override | |
| 893 | - public void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, | |
| 894 | - String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 895 | - | |
| 896 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 897 | - String charset = device.getCharset(); | |
| 898 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 899 | - cmdXml.append("<Control>\r\n"); | |
| 900 | - cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n"); | |
| 901 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 902 | - if (ObjectUtils.isEmpty(channelId)) { | |
| 903 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 904 | - } else { | |
| 905 | - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 906 | - } | |
| 907 | - cmdXml.append("<BasicParam>\r\n"); | |
| 908 | - if (!ObjectUtils.isEmpty(name)) { | |
| 909 | - cmdXml.append("<Name>" + name + "</Name>\r\n"); | |
| 910 | - } | |
| 911 | - if (NumericUtil.isInteger(expiration)) { | |
| 912 | - if (Integer.valueOf(expiration) > 0) { | |
| 913 | - cmdXml.append("<Expiration>" + expiration + "</Expiration>\r\n"); | |
| 914 | - } | |
| 915 | - } | |
| 916 | - if (NumericUtil.isInteger(heartBeatInterval)) { | |
| 917 | - if (Integer.valueOf(heartBeatInterval) > 0) { | |
| 918 | - cmdXml.append("<HeartBeatInterval>" + heartBeatInterval + "</HeartBeatInterval>\r\n"); | |
| 919 | - } | |
| 920 | - } | |
| 921 | - if (NumericUtil.isInteger(heartBeatCount)) { | |
| 922 | - if (Integer.valueOf(heartBeatCount) > 0) { | |
| 923 | - cmdXml.append("<HeartBeatCount>" + heartBeatCount + "</HeartBeatCount>\r\n"); | |
| 924 | - } | |
| 925 | - } | |
| 926 | - cmdXml.append("</BasicParam>\r\n"); | |
| 927 | - cmdXml.append("</Control>\r\n"); | |
| 928 | - | |
| 929 | - | |
| 930 | - | |
| 931 | - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 932 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 933 | - } | |
| 934 | - | |
| 935 | - /** | |
| 936 | - * 查询设备状态 | |
| 937 | - * | |
| 938 | - * @param device 视频设备 | |
| 939 | - */ | |
| 940 | - @Override | |
| 941 | - public void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 942 | - | |
| 943 | - String charset = device.getCharset(); | |
| 944 | - StringBuffer catalogXml = new StringBuffer(200); | |
| 945 | - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 946 | - catalogXml.append("<Query>\r\n"); | |
| 947 | - catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n"); | |
| 948 | - catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 949 | - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 950 | - catalogXml.append("</Query>\r\n"); | |
| 951 | - | |
| 952 | - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 953 | - | |
| 954 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 955 | - } | |
| 956 | - | |
| 957 | - /** | |
| 958 | - * 查询设备信息 | |
| 959 | - * | |
| 960 | - * @param device 视频设备 | |
| 961 | - */ | |
| 962 | - @Override | |
| 963 | - public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException { | |
| 964 | - | |
| 965 | - StringBuffer catalogXml = new StringBuffer(200); | |
| 966 | - String charset = device.getCharset(); | |
| 967 | - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 968 | - catalogXml.append("<Query>\r\n"); | |
| 969 | - catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n"); | |
| 970 | - catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 971 | - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 972 | - catalogXml.append("</Query>\r\n"); | |
| 973 | - | |
| 974 | - | |
| 975 | - | |
| 976 | - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 977 | - | |
| 978 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); | |
| 979 | - | |
| 980 | - } | |
| 981 | - | |
| 982 | - /** | |
| 983 | - * 查询目录列表 | |
| 984 | - * | |
| 985 | - * @param device 视频设备 | |
| 986 | - */ | |
| 987 | - @Override | |
| 988 | - public void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException { | |
| 989 | - | |
| 990 | - StringBuffer catalogXml = new StringBuffer(200); | |
| 991 | - String charset = device.getCharset(); | |
| 992 | - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 993 | - catalogXml.append("<Query>\r\n"); | |
| 994 | - catalogXml.append(" <CmdType>Catalog</CmdType>\r\n"); | |
| 995 | - catalogXml.append(" <SN>" + sn + "</SN>\r\n"); | |
| 996 | - catalogXml.append(" <DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 997 | - catalogXml.append("</Query>\r\n"); | |
| 998 | - | |
| 999 | - | |
| 1000 | - | |
| 1001 | - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1002 | - | |
| 1003 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 1004 | - } | |
| 1005 | - | |
| 1006 | - /** | |
| 1007 | - * 查询录像信息 | |
| 1008 | - * | |
| 1009 | - * @param device 视频设备 | |
| 1010 | - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 1011 | - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 1012 | - */ | |
| 1013 | - @Override | |
| 1014 | - 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 { | |
| 1015 | - if (secrecy == null) { | |
| 1016 | - secrecy = 0; | |
| 1017 | - } | |
| 1018 | - if (type == null) { | |
| 1019 | - type = "all"; | |
| 1020 | - } | |
| 1021 | - | |
| 1022 | - StringBuffer recordInfoXml = new StringBuffer(200); | |
| 1023 | - String charset = device.getCharset(); | |
| 1024 | - recordInfoXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1025 | - recordInfoXml.append("<Query>\r\n"); | |
| 1026 | - recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n"); | |
| 1027 | - recordInfoXml.append("<SN>" + sn + "</SN>\r\n"); | |
| 1028 | - recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 1029 | - if (startTime != null) { | |
| 1030 | - recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n"); | |
| 1031 | - } | |
| 1032 | - if (endTime != null) { | |
| 1033 | - recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n"); | |
| 1034 | - } | |
| 1035 | - if (secrecy != null) { | |
| 1036 | - recordInfoXml.append("<Secrecy> " + secrecy + " </Secrecy>\r\n"); | |
| 1037 | - } | |
| 1038 | - if (type != null) { | |
| 1039 | - // 大华NVR要求必须增加一个值为all的文本元素节点Type | |
| 1040 | - recordInfoXml.append("<Type>" + type + "</Type>\r\n"); | |
| 1041 | - } | |
| 1042 | - recordInfoXml.append("</Query>\r\n"); | |
| 1043 | - | |
| 1044 | - | |
| 1045 | - | |
| 1046 | - Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), | |
| 1047 | - SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1048 | - | |
| 1049 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); | |
| 1050 | - } | |
| 1051 | - | |
| 1052 | - /** | |
| 1053 | - * 查询报警信息 | |
| 1054 | - * | |
| 1055 | - * @param device 视频设备 | |
| 1056 | - * @param startPriority 报警起始级别(可选) | |
| 1057 | - * @param endPriority 报警终止级别(可选) | |
| 1058 | - * @param alarmMethod 报警方式条件(可选) | |
| 1059 | - * @param alarmType 报警类型 | |
| 1060 | - * @param startTime 报警发生起始时间(可选) | |
| 1061 | - * @param endTime 报警发生终止时间(可选) | |
| 1062 | - * @return true = 命令发送成功 | |
| 1063 | - */ | |
| 1064 | - @Override | |
| 1065 | - public void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, | |
| 1066 | - String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1067 | - | |
| 1068 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 1069 | - String charset = device.getCharset(); | |
| 1070 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1071 | - cmdXml.append("<Query>\r\n"); | |
| 1072 | - cmdXml.append("<CmdType>Alarm</CmdType>\r\n"); | |
| 1073 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1074 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1075 | - if (!ObjectUtils.isEmpty(startPriority)) { | |
| 1076 | - cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n"); | |
| 1077 | - } | |
| 1078 | - if (!ObjectUtils.isEmpty(endPriority)) { | |
| 1079 | - cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n"); | |
| 1080 | - } | |
| 1081 | - if (!ObjectUtils.isEmpty(alarmMethod)) { | |
| 1082 | - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n"); | |
| 1083 | - } | |
| 1084 | - if (!ObjectUtils.isEmpty(alarmType)) { | |
| 1085 | - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n"); | |
| 1086 | - } | |
| 1087 | - if (!ObjectUtils.isEmpty(startTime)) { | |
| 1088 | - cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n"); | |
| 1089 | - } | |
| 1090 | - if (!ObjectUtils.isEmpty(endTime)) { | |
| 1091 | - cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n"); | |
| 1092 | - } | |
| 1093 | - cmdXml.append("</Query>\r\n"); | |
| 1094 | - | |
| 1095 | - | |
| 1096 | - | |
| 1097 | - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1098 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 1099 | - } | |
| 1100 | - | |
| 1101 | - /** | |
| 1102 | - * 查询设备配置 | |
| 1103 | - * | |
| 1104 | - * @param device 视频设备 | |
| 1105 | - * @param channelId 通道编码(可选) | |
| 1106 | - * @param configType 配置类型: | |
| 1107 | - */ | |
| 1108 | - @Override | |
| 1109 | - public void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1110 | - | |
| 1111 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 1112 | - String charset = device.getCharset(); | |
| 1113 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1114 | - cmdXml.append("<Query>\r\n"); | |
| 1115 | - cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n"); | |
| 1116 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1117 | - if (ObjectUtils.isEmpty(channelId)) { | |
| 1118 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1119 | - } else { | |
| 1120 | - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 1121 | - } | |
| 1122 | - cmdXml.append("<ConfigType>" + configType + "</ConfigType>\r\n"); | |
| 1123 | - cmdXml.append("</Query>\r\n"); | |
| 1124 | - | |
| 1125 | - | |
| 1126 | - | |
| 1127 | - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1128 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 1129 | - } | |
| 1130 | - | |
| 1131 | - /** | |
| 1132 | - * 查询设备预置位置 | |
| 1133 | - * | |
| 1134 | - * @param device 视频设备 | |
| 1135 | - */ | |
| 1136 | - @Override | |
| 1137 | - public void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1138 | - | |
| 1139 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 1140 | - String charset = device.getCharset(); | |
| 1141 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1142 | - cmdXml.append("<Query>\r\n"); | |
| 1143 | - cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n"); | |
| 1144 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1145 | - if (ObjectUtils.isEmpty(channelId)) { | |
| 1146 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1147 | - } else { | |
| 1148 | - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 1149 | - } | |
| 1150 | - cmdXml.append("</Query>\r\n"); | |
| 1151 | - | |
| 1152 | - | |
| 1153 | - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1154 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 1155 | - } | |
| 1156 | - | |
| 1157 | - /** | |
| 1158 | - * 查询移动设备位置数据 | |
| 1159 | - * | |
| 1160 | - * @param device 视频设备 | |
| 1161 | - */ | |
| 1162 | - @Override | |
| 1163 | - public void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1164 | - | |
| 1165 | - StringBuffer mobilePostitionXml = new StringBuffer(200); | |
| 1166 | - String charset = device.getCharset(); | |
| 1167 | - mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1168 | - mobilePostitionXml.append("<Query>\r\n"); | |
| 1169 | - mobilePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n"); | |
| 1170 | - mobilePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1171 | - mobilePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1172 | - mobilePostitionXml.append("<Interval>60</Interval>\r\n"); | |
| 1173 | - mobilePostitionXml.append("</Query>\r\n"); | |
| 1174 | - | |
| 1175 | - | |
| 1176 | - | |
| 1177 | - Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1178 | - | |
| 1179 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 1180 | - | |
| 1181 | - } | |
| 1182 | - | |
| 1183 | - /** | |
| 1184 | - * 订阅、取消订阅移动位置 | |
| 1185 | - * | |
| 1186 | - * @param device 视频设备 | |
| 1187 | - * @return true = 命令发送成功 | |
| 1188 | - */ | |
| 1189 | - @Override | |
| 1190 | - public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1191 | - | |
| 1192 | - StringBuffer subscribePostitionXml = new StringBuffer(200); | |
| 1193 | - String charset = device.getCharset(); | |
| 1194 | - subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1195 | - subscribePostitionXml.append("<Query>\r\n"); | |
| 1196 | - subscribePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n"); | |
| 1197 | - subscribePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1198 | - subscribePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1199 | - if (device.getSubscribeCycleForMobilePosition() > 0) { | |
| 1200 | - subscribePostitionXml.append("<Interval>" + device.getMobilePositionSubmissionInterval() + "</Interval>\r\n"); | |
| 1201 | - } | |
| 1202 | - subscribePostitionXml.append("</Query>\r\n"); | |
| 1203 | - | |
| 1204 | - CallIdHeader callIdHeader; | |
| 1205 | - | |
| 1206 | - if (requestOld != null) { | |
| 1207 | - callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); | |
| 1208 | - } else { | |
| 1209 | - callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); | |
| 1210 | - } | |
| 1211 | - SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence",callIdHeader); //Position;id=" + tm.substring(tm.length() - 4)); | |
| 1212 | - | |
| 1213 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); | |
| 1214 | - return request; | |
| 1215 | - } | |
| 1216 | - | |
| 1217 | - /** | |
| 1218 | - * 订阅、取消订阅报警信息 | |
| 1219 | - * | |
| 1220 | - * @param device 视频设备 | |
| 1221 | - * @param expires 订阅过期时间(0 = 取消订阅) | |
| 1222 | - * @param startPriority 报警起始级别(可选) | |
| 1223 | - * @param endPriority 报警终止级别(可选) | |
| 1224 | - * @param alarmMethod 报警方式条件(可选) | |
| 1225 | - * @param alarmType 报警类型 | |
| 1226 | - * @param startTime 报警发生起始时间(可选) | |
| 1227 | - * @param endTime 报警发生终止时间(可选) | |
| 1228 | - * @return true = 命令发送成功 | |
| 1229 | - */ | |
| 1230 | - @Override | |
| 1231 | - public void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException { | |
| 1232 | - | |
| 1233 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 1234 | - String charset = device.getCharset(); | |
| 1235 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1236 | - cmdXml.append("<Query>\r\n"); | |
| 1237 | - cmdXml.append("<CmdType>Alarm</CmdType>\r\n"); | |
| 1238 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1239 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1240 | - if (!ObjectUtils.isEmpty(startPriority)) { | |
| 1241 | - cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n"); | |
| 1242 | - } | |
| 1243 | - if (!ObjectUtils.isEmpty(endPriority)) { | |
| 1244 | - cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n"); | |
| 1245 | - } | |
| 1246 | - if (!ObjectUtils.isEmpty(alarmMethod)) { | |
| 1247 | - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n"); | |
| 1248 | - } | |
| 1249 | - if (!ObjectUtils.isEmpty(startTime)) { | |
| 1250 | - cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n"); | |
| 1251 | - } | |
| 1252 | - if (!ObjectUtils.isEmpty(endTime)) { | |
| 1253 | - cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n"); | |
| 1254 | - } | |
| 1255 | - cmdXml.append("</Query>\r\n"); | |
| 1256 | - | |
| 1257 | - | |
| 1258 | - | |
| 1259 | - Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence",sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1260 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); | |
| 1261 | - | |
| 1262 | - } | |
| 1263 | - | |
| 1264 | - @Override | |
| 1265 | - public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1266 | - | |
| 1267 | - StringBuffer cmdXml = new StringBuffer(200); | |
| 1268 | - String charset = device.getCharset(); | |
| 1269 | - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1270 | - cmdXml.append("<Query>\r\n"); | |
| 1271 | - cmdXml.append("<CmdType>Catalog</CmdType>\r\n"); | |
| 1272 | - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1273 | - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1274 | - cmdXml.append("</Query>\r\n"); | |
| 1275 | - | |
| 1276 | - CallIdHeader callIdHeader; | |
| 1277 | - | |
| 1278 | - if (requestOld != null) { | |
| 1279 | - callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); | |
| 1280 | - } else { | |
| 1281 | - callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); | |
| 1282 | - } | |
| 1283 | - | |
| 1284 | - // 有效时间默认为60秒以上 | |
| 1285 | - SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog", | |
| 1286 | - callIdHeader); | |
| 1287 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); | |
| 1288 | - return request; | |
| 1289 | - } | |
| 1290 | - | |
| 1291 | - @Override | |
| 1292 | - public void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException { | |
| 1293 | - | |
| 1294 | - StringBuffer dragXml = new StringBuffer(200); | |
| 1295 | - String charset = device.getCharset(); | |
| 1296 | - dragXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1297 | - dragXml.append("<Control>\r\n"); | |
| 1298 | - dragXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 1299 | - dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1300 | - if (ObjectUtils.isEmpty(channelId)) { | |
| 1301 | - dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1302 | - } else { | |
| 1303 | - dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 1304 | - } | |
| 1305 | - dragXml.append(cmdString); | |
| 1306 | - dragXml.append("</Control>\r\n"); | |
| 1307 | - | |
| 1308 | - Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1309 | - logger.debug("拉框信令: " + request.toString()); | |
| 1310 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); | |
| 1311 | - } | |
| 1312 | - | |
| 1313 | - | |
| 1314 | - | |
| 1315 | - | |
| 1316 | - | |
| 1317 | - /** | |
| 1318 | - * 回放暂停 | |
| 1319 | - */ | |
| 1320 | - @Override | |
| 1321 | - public void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException { | |
| 1322 | - StringBuffer content = new StringBuffer(200); | |
| 1323 | - content.append("PAUSE RTSP/1.0\r\n"); | |
| 1324 | - content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1325 | - content.append("PauseTime: now\r\n"); | |
| 1326 | - | |
| 1327 | - playbackControlCmd(device, streamInfo, content.toString(), null, null); | |
| 1328 | - } | |
| 1329 | - | |
| 1330 | - | |
| 1331 | - /** | |
| 1332 | - * 回放恢复 | |
| 1333 | - */ | |
| 1334 | - @Override | |
| 1335 | - public void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException { | |
| 1336 | - StringBuffer content = new StringBuffer(200); | |
| 1337 | - content.append("PLAY RTSP/1.0\r\n"); | |
| 1338 | - content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1339 | - content.append("Range: npt=now-\r\n"); | |
| 1340 | - | |
| 1341 | - playbackControlCmd(device, streamInfo, content.toString(), null, null); | |
| 1342 | - } | |
| 1343 | - | |
| 1344 | - /** | |
| 1345 | - * 回放拖动播放 | |
| 1346 | - */ | |
| 1347 | - @Override | |
| 1348 | - public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException { | |
| 1349 | - StringBuffer content = new StringBuffer(200); | |
| 1350 | - content.append("PLAY RTSP/1.0\r\n"); | |
| 1351 | - content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1352 | - content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n"); | |
| 1353 | - | |
| 1354 | - playbackControlCmd(device, streamInfo, content.toString(), null, null); | |
| 1355 | - } | |
| 1356 | - | |
| 1357 | - /** | |
| 1358 | - * 回放倍速播放 | |
| 1359 | - */ | |
| 1360 | - @Override | |
| 1361 | - public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException { | |
| 1362 | - StringBuffer content = new StringBuffer(200); | |
| 1363 | - content.append("PLAY RTSP/1.0\r\n"); | |
| 1364 | - content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1365 | - content.append("Scale: " + String.format("%.6f", speed) + "\r\n"); | |
| 1366 | - | |
| 1367 | - playbackControlCmd(device, streamInfo, content.toString(), null, null); | |
| 1368 | - } | |
| 1369 | - | |
| 1370 | - private int getInfoCseq() { | |
| 1371 | - return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8)); | |
| 1372 | - } | |
| 1373 | - | |
| 1374 | - @Override | |
| 1375 | - public void playbackControlCmd(Device device, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException { | |
| 1376 | - | |
| 1377 | - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), streamInfo.getChannelId(), null, streamInfo.getStream()); | |
| 1378 | - if (ssrcTransaction == null) { | |
| 1379 | - logger.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); | |
| 1380 | - return; | |
| 1381 | - } | |
| 1382 | - | |
| 1383 | - SIPRequest request = headerProvider.createInfoRequest(device, streamInfo.getChannelId(), content.toString(), ssrcTransaction.getSipTransactionInfo()); | |
| 1384 | - if (request == null) { | |
| 1385 | - logger.info("[回放控制]构建Request信息失败,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); | |
| 1386 | - return; | |
| 1387 | - } | |
| 1388 | - | |
| 1389 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); | |
| 1390 | - } | |
| 1391 | - | |
| 1392 | - @Override | |
| 1393 | - public void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException { | |
| 1394 | - if (device == null) { | |
| 1395 | - return; | |
| 1396 | - } | |
| 1397 | - logger.info("[发送报警通知]设备: {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(), | |
| 1398 | - deviceAlarm.getLongitude(), deviceAlarm.getLatitude()); | |
| 1399 | - | |
| 1400 | - String characterSet = device.getCharset(); | |
| 1401 | - StringBuffer deviceStatusXml = new StringBuffer(600); | |
| 1402 | - deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n"); | |
| 1403 | - deviceStatusXml.append("<Notify>\r\n"); | |
| 1404 | - deviceStatusXml.append("<CmdType>Alarm</CmdType>\r\n"); | |
| 1405 | - deviceStatusXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1406 | - deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n"); | |
| 1407 | - deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n"); | |
| 1408 | - deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n"); | |
| 1409 | - deviceStatusXml.append("<AlarmTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(deviceAlarm.getAlarmTime()) + "</AlarmTime>\r\n"); | |
| 1410 | - deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n"); | |
| 1411 | - deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n"); | |
| 1412 | - deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n"); | |
| 1413 | - deviceStatusXml.append("<info>\r\n"); | |
| 1414 | - deviceStatusXml.append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n"); | |
| 1415 | - deviceStatusXml.append("</info>\r\n"); | |
| 1416 | - deviceStatusXml.append("</Notify>\r\n"); | |
| 1417 | - | |
| 1418 | - | |
| 1419 | - Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1420 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); | |
| 1421 | - | |
| 1422 | - | |
| 1423 | - } | |
| 1424 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.common.InviteSessionType; | |
| 4 | +import com.genersoft.iot.vmp.common.StreamInfo; | |
| 5 | +import com.genersoft.iot.vmp.conf.SipConfig; | |
| 6 | +import com.genersoft.iot.vmp.conf.UserSetting; | |
| 7 | +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.SipLayer; | |
| 9 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 10 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; | |
| 11 | +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; | |
| 12 | +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | |
| 13 | +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 14 | +import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; | |
| 15 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; | |
| 16 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; | |
| 17 | +import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; | |
| 18 | +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | |
| 19 | +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | |
| 20 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | |
| 21 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | |
| 22 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 23 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; | |
| 24 | +import com.genersoft.iot.vmp.service.IMediaServerService; | |
| 25 | +import com.genersoft.iot.vmp.service.bean.SSRCInfo; | |
| 26 | +import com.genersoft.iot.vmp.utils.DateUtil; | |
| 27 | +import gov.nist.javax.sip.message.SIPRequest; | |
| 28 | +import gov.nist.javax.sip.message.SIPResponse; | |
| 29 | +import org.slf4j.Logger; | |
| 30 | +import org.slf4j.LoggerFactory; | |
| 31 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 32 | +import org.springframework.context.annotation.DependsOn; | |
| 33 | +import org.springframework.stereotype.Component; | |
| 34 | +import org.springframework.util.ObjectUtils; | |
| 35 | + | |
| 36 | +import javax.sip.InvalidArgumentException; | |
| 37 | +import javax.sip.ResponseEvent; | |
| 38 | +import javax.sip.SipException; | |
| 39 | +import javax.sip.SipFactory; | |
| 40 | +import javax.sip.header.CallIdHeader; | |
| 41 | +import javax.sip.message.Request; | |
| 42 | +import java.text.ParseException; | |
| 43 | + | |
| 44 | +/** | |
| 45 | + * @description:设备能力接口,用于定义设备的控制、查询能力 | |
| 46 | + * @author: swwheihei | |
| 47 | + * @date: 2020年5月3日 下午9:22:48 | |
| 48 | + */ | |
| 49 | +@Component | |
| 50 | +@DependsOn("sipLayer") | |
| 51 | +public class SIPCommander implements ISIPCommander { | |
| 52 | + | |
| 53 | + private final Logger logger = LoggerFactory.getLogger(SIPCommander.class); | |
| 54 | + | |
| 55 | + @Autowired | |
| 56 | + private SipConfig sipConfig; | |
| 57 | + | |
| 58 | + @Autowired | |
| 59 | + private SipLayer sipLayer; | |
| 60 | + | |
| 61 | + @Autowired | |
| 62 | + private SIPSender sipSender; | |
| 63 | + | |
| 64 | + @Autowired | |
| 65 | + private SIPRequestHeaderProvider headerProvider; | |
| 66 | + | |
| 67 | + @Autowired | |
| 68 | + private VideoStreamSessionManager streamSession; | |
| 69 | + | |
| 70 | + @Autowired | |
| 71 | + private UserSetting userSetting; | |
| 72 | + | |
| 73 | + @Autowired | |
| 74 | + private ZlmHttpHookSubscribe subscribe; | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + @Autowired | |
| 79 | + private IMediaServerService mediaServerService; | |
| 80 | + | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * 云台方向放控制,使用配置文件中的默认镜头移动速度 | |
| 84 | + * | |
| 85 | + * @param device 控制设备 | |
| 86 | + * @param channelId 预览通道 | |
| 87 | + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 88 | + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 89 | + */ | |
| 90 | + @Override | |
| 91 | + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException { | |
| 92 | + ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0); | |
| 93 | + } | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * 云台方向放控制 | |
| 97 | + * | |
| 98 | + * @param device 控制设备 | |
| 99 | + * @param channelId 预览通道 | |
| 100 | + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 101 | + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 102 | + * @param moveSpeed 镜头移动速度 | |
| 103 | + */ | |
| 104 | + @Override | |
| 105 | + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException { | |
| 106 | + ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0); | |
| 107 | + } | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * 云台缩放控制,使用配置文件中的默认镜头缩放速度 | |
| 111 | + * | |
| 112 | + * @param device 控制设备 | |
| 113 | + * @param channelId 预览通道 | |
| 114 | + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 115 | + */ | |
| 116 | + @Override | |
| 117 | + public void ptzZoomCmd(Device device, String channelId, int inOut) throws InvalidArgumentException, ParseException, SipException { | |
| 118 | + ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed()); | |
| 119 | + } | |
| 120 | + | |
| 121 | + /** | |
| 122 | + * 云台缩放控制 | |
| 123 | + * | |
| 124 | + * @param device 控制设备 | |
| 125 | + * @param channelId 预览通道 | |
| 126 | + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 127 | + * @param zoomSpeed 镜头缩放速度 | |
| 128 | + */ | |
| 129 | + @Override | |
| 130 | + public void ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) throws InvalidArgumentException, ParseException, SipException { | |
| 131 | + ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed); | |
| 132 | + } | |
| 133 | + | |
| 134 | + /** | |
| 135 | + * 云台指令码计算 | |
| 136 | + * | |
| 137 | + * @param cmdCode 指令码 | |
| 138 | + * @param parameter1 数据1 | |
| 139 | + * @param parameter2 数据2 | |
| 140 | + * @param combineCode2 组合码2 | |
| 141 | + */ | |
| 142 | + public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) { | |
| 143 | + StringBuilder builder = new StringBuilder("A50F01"); | |
| 144 | + String strTmp; | |
| 145 | + strTmp = String.format("%02X", cmdCode); | |
| 146 | + builder.append(strTmp, 0, 2); | |
| 147 | + strTmp = String.format("%02X", parameter1); | |
| 148 | + builder.append(strTmp, 0, 2); | |
| 149 | + strTmp = String.format("%02X", parameter2); | |
| 150 | + builder.append(strTmp, 0, 2); | |
| 151 | + //优化zoom变倍速率 | |
| 152 | + if ((combineCode2 > 0) && (combineCode2 <16)) | |
| 153 | + { | |
| 154 | + combineCode2 = 16; | |
| 155 | + } | |
| 156 | + strTmp = String.format("%X", combineCode2); | |
| 157 | + builder.append(strTmp, 0, 1).append("0"); | |
| 158 | + //计算校验码 | |
| 159 | + int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100; | |
| 160 | + strTmp = String.format("%02X", checkCode); | |
| 161 | + builder.append(strTmp, 0, 2); | |
| 162 | + return builder.toString(); | |
| 163 | + } | |
| 164 | + | |
| 165 | + /** | |
| 166 | + * 云台控制,支持方向与缩放控制 | |
| 167 | + * | |
| 168 | + * @param device 控制设备 | |
| 169 | + * @param channelId 预览通道 | |
| 170 | + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 | |
| 171 | + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 | |
| 172 | + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 | |
| 173 | + * @param moveSpeed 镜头移动速度 | |
| 174 | + * @param zoomSpeed 镜头缩放速度 | |
| 175 | + */ | |
| 176 | + @Override | |
| 177 | + public void ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed, | |
| 178 | + int zoomSpeed) throws InvalidArgumentException, SipException, ParseException { | |
| 179 | + String cmdStr = SipUtils.cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed); | |
| 180 | + StringBuilder ptzXml = new StringBuilder(200); | |
| 181 | + String charset = device.getCharset(); | |
| 182 | + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 183 | + ptzXml.append("<Control>\r\n"); | |
| 184 | + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 185 | + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 186 | + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 187 | + ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n"); | |
| 188 | + ptzXml.append("<Info>\r\n"); | |
| 189 | + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n"); | |
| 190 | + ptzXml.append("</Info>\r\n"); | |
| 191 | + ptzXml.append("</Control>\r\n"); | |
| 192 | + | |
| 193 | + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 194 | + | |
| 195 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); | |
| 196 | + } | |
| 197 | + | |
| 198 | + /** | |
| 199 | + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 | |
| 200 | + * | |
| 201 | + * @param device 控制设备 | |
| 202 | + * @param channelId 预览通道 | |
| 203 | + * @param cmdCode 指令码 | |
| 204 | + * @param parameter1 数据1 | |
| 205 | + * @param parameter2 数据2 | |
| 206 | + * @param combineCode2 组合码2 | |
| 207 | + */ | |
| 208 | + @Override | |
| 209 | + public void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException { | |
| 210 | + | |
| 211 | + String cmdStr = frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2); | |
| 212 | + StringBuffer ptzXml = new StringBuffer(200); | |
| 213 | + String charset = device.getCharset(); | |
| 214 | + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 215 | + ptzXml.append("<Control>\r\n"); | |
| 216 | + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 217 | + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 218 | + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 219 | + ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n"); | |
| 220 | + ptzXml.append("<Info>\r\n"); | |
| 221 | + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n"); | |
| 222 | + ptzXml.append("</Info>\r\n"); | |
| 223 | + ptzXml.append("</Control>\r\n"); | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 229 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); | |
| 230 | + | |
| 231 | + } | |
| 232 | + | |
| 233 | + /** | |
| 234 | + * 前端控制指令(用于转发上级指令) | |
| 235 | + * | |
| 236 | + * @param device 控制设备 | |
| 237 | + * @param channelId 预览通道 | |
| 238 | + * @param cmdString 前端控制指令串 | |
| 239 | + */ | |
| 240 | + @Override | |
| 241 | + public void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 242 | + | |
| 243 | + StringBuffer ptzXml = new StringBuffer(200); | |
| 244 | + String charset = device.getCharset(); | |
| 245 | + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 246 | + ptzXml.append("<Control>\r\n"); | |
| 247 | + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 248 | + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 249 | + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 250 | + ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n"); | |
| 251 | + ptzXml.append("<Info>\r\n"); | |
| 252 | + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n"); | |
| 253 | + ptzXml.append("</Info>\r\n"); | |
| 254 | + ptzXml.append("</Control>\r\n"); | |
| 255 | + | |
| 256 | + | |
| 257 | + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 258 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request, errorEvent, okEvent); | |
| 259 | + | |
| 260 | + } | |
| 261 | + | |
| 262 | + /** | |
| 263 | + * 请求预览视频流 | |
| 264 | + * | |
| 265 | + * @param device 视频设备 | |
| 266 | + * @param channelId 预览通道 | |
| 267 | + * @param event hook订阅 | |
| 268 | + * @param errorEvent sip错误订阅 | |
| 269 | + */ | |
| 270 | + @Override | |
| 271 | + public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | |
| 272 | + ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 273 | + String stream = ssrcInfo.getStream(); | |
| 274 | + | |
| 275 | + if (device == null) { | |
| 276 | + return; | |
| 277 | + } | |
| 278 | + | |
| 279 | + logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); | |
| 280 | + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); | |
| 281 | + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> { | |
| 282 | + if (event != null) { | |
| 283 | + event.response(mediaServerItemInUse, hookParam); | |
| 284 | + subscribe.removeSubscribe(hookSubscribe); | |
| 285 | + } | |
| 286 | + }); | |
| 287 | + String sdpIp; | |
| 288 | + if (!ObjectUtils.isEmpty(device.getSdpIp())) { | |
| 289 | + sdpIp = device.getSdpIp(); | |
| 290 | + }else { | |
| 291 | + sdpIp = mediaServerItem.getSdpIp(); | |
| 292 | + } | |
| 293 | + StringBuffer content = new StringBuffer(200); | |
| 294 | + content.append("v=0\r\n"); | |
| 295 | + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); | |
| 296 | + content.append("s=Play\r\n"); | |
| 297 | + content.append("c=IN IP4 " + sdpIp + "\r\n"); | |
| 298 | + content.append("t=0 0\r\n"); | |
| 299 | + | |
| 300 | + if (userSetting.isSeniorSdp()) { | |
| 301 | + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { | |
| 302 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 303 | + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { | |
| 304 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 305 | + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) { | |
| 306 | + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 307 | + } | |
| 308 | + content.append("a=recvonly\r\n"); | |
| 309 | + content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 310 | + content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); | |
| 311 | + content.append("a=rtpmap:126 H264/90000\r\n"); | |
| 312 | + content.append("a=rtpmap:125 H264S/90000\r\n"); | |
| 313 | + content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); | |
| 314 | + content.append("a=rtpmap:99 H265/90000\r\n"); | |
| 315 | + content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 316 | + content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 317 | + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式 | |
| 318 | + content.append("a=setup:passive\r\n"); | |
| 319 | + content.append("a=connection:new\r\n"); | |
| 320 | + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 | |
| 321 | + content.append("a=setup:active\r\n"); | |
| 322 | + content.append("a=connection:new\r\n"); | |
| 323 | + } | |
| 324 | + } else { | |
| 325 | + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { | |
| 326 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 327 | + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { | |
| 328 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 329 | + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) { | |
| 330 | + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); | |
| 331 | + } | |
| 332 | + content.append("a=recvonly\r\n"); | |
| 333 | + content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 334 | + content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 335 | + content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 336 | + content.append("a=rtpmap:99 H265/90000\r\n"); | |
| 337 | + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式 | |
| 338 | + content.append("a=setup:passive\r\n"); | |
| 339 | + content.append("a=connection:new\r\n"); | |
| 340 | + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式 | |
| 341 | + content.append("a=setup:active\r\n"); | |
| 342 | + content.append("a=connection:new\r\n"); | |
| 343 | + } | |
| 344 | + } | |
| 345 | + | |
| 346 | + if( device.isSwitchPrimarySubStream() ){ | |
| 347 | + if("TP-LINK".equals(device.getManufacturer())){ | |
| 348 | + if (device.isSwitchPrimarySubStream()){ | |
| 349 | + content.append("a=streamMode:sub\r\n"); | |
| 350 | + }else { | |
| 351 | + content.append("a=streamMode:main\r\n"); | |
| 352 | + } | |
| 353 | + }else { | |
| 354 | + if (device.isSwitchPrimarySubStream()){ | |
| 355 | + content.append("a=streamprofile:1\r\n"); | |
| 356 | + }else { | |
| 357 | + content.append("a=streamprofile:0\r\n"); | |
| 358 | + } | |
| 359 | + } | |
| 360 | + } | |
| 361 | + | |
| 362 | + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc | |
| 363 | + // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率 | |
| 364 | +// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备 | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 369 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> { | |
| 370 | + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 371 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 372 | + errorEvent.response(e); | |
| 373 | + }), e -> { | |
| 374 | + ResponseEvent responseEvent = (ResponseEvent) e.event; | |
| 375 | + SIPResponse response = (SIPResponse) responseEvent.getResponse(); | |
| 376 | + streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, | |
| 377 | + InviteSessionType.PLAY); | |
| 378 | + okEvent.response(e); | |
| 379 | + }); | |
| 380 | + } | |
| 381 | + | |
| 382 | + /** | |
| 383 | + * 请求回放视频流 | |
| 384 | + * | |
| 385 | + * @param device 视频设备 | |
| 386 | + * @param channelId 预览通道 | |
| 387 | + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 388 | + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 389 | + */ | |
| 390 | + @Override | |
| 391 | + public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | |
| 392 | + String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent, | |
| 393 | + SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 394 | + | |
| 395 | + | |
| 396 | + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); | |
| 397 | + String sdpIp; | |
| 398 | + if (!ObjectUtils.isEmpty(device.getSdpIp())) { | |
| 399 | + sdpIp = device.getSdpIp(); | |
| 400 | + }else { | |
| 401 | + sdpIp = mediaServerItem.getSdpIp(); | |
| 402 | + } | |
| 403 | + StringBuffer content = new StringBuffer(200); | |
| 404 | + content.append("v=0\r\n"); | |
| 405 | + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); | |
| 406 | + content.append("s=Playback\r\n"); | |
| 407 | + content.append("u=" + channelId + ":0\r\n"); | |
| 408 | + content.append("c=IN IP4 " + sdpIp + "\r\n"); | |
| 409 | + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " " | |
| 410 | + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n"); | |
| 411 | + | |
| 412 | + String streamMode = device.getStreamMode(); | |
| 413 | + | |
| 414 | + if (userSetting.isSeniorSdp()) { | |
| 415 | + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { | |
| 416 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 417 | + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { | |
| 418 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 419 | + } else if ("UDP".equalsIgnoreCase(streamMode)) { | |
| 420 | + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 421 | + } | |
| 422 | + content.append("a=recvonly\r\n"); | |
| 423 | + content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 424 | + content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); | |
| 425 | + content.append("a=rtpmap:126 H264/90000\r\n"); | |
| 426 | + content.append("a=rtpmap:125 H264S/90000\r\n"); | |
| 427 | + content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); | |
| 428 | + content.append("a=rtpmap:99 H265/90000\r\n"); | |
| 429 | + content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 430 | + content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 431 | + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式 | |
| 432 | + content.append("a=setup:passive\r\n"); | |
| 433 | + content.append("a=connection:new\r\n"); | |
| 434 | + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式 | |
| 435 | + content.append("a=setup:active\r\n"); | |
| 436 | + content.append("a=connection:new\r\n"); | |
| 437 | + } | |
| 438 | + } else { | |
| 439 | + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { | |
| 440 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 441 | + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { | |
| 442 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 443 | + } else if ("UDP".equalsIgnoreCase(streamMode)) { | |
| 444 | + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); | |
| 445 | + } | |
| 446 | + content.append("a=recvonly\r\n"); | |
| 447 | + content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 448 | + content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 449 | + content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 450 | + content.append("a=rtpmap:99 H265/90000\r\n"); | |
| 451 | + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { | |
| 452 | + // tcp被动模式 | |
| 453 | + content.append("a=setup:passive\r\n"); | |
| 454 | + content.append("a=connection:new\r\n"); | |
| 455 | + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { | |
| 456 | + // tcp主动模式 | |
| 457 | + content.append("a=setup:active\r\n"); | |
| 458 | + content.append("a=connection:new\r\n"); | |
| 459 | + } | |
| 460 | + } | |
| 461 | + | |
| 462 | + //ssrc | |
| 463 | + content.append("y=" + ssrcInfo.getSsrc() + "\r\n"); | |
| 464 | + | |
| 465 | + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); | |
| 466 | + // 添加订阅 | |
| 467 | + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> { | |
| 468 | + if (hookEvent != null) { | |
| 469 | + hookEvent.response(mediaServerItemInUse, hookParam); | |
| 470 | + } | |
| 471 | + subscribe.removeSubscribe(hookSubscribe); | |
| 472 | + }); | |
| 473 | + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc()); | |
| 474 | + | |
| 475 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { | |
| 476 | + ResponseEvent responseEvent = (ResponseEvent) event.event; | |
| 477 | + SIPResponse response = (SIPResponse) responseEvent.getResponse(); | |
| 478 | + streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK); | |
| 479 | + okEvent.response(event); | |
| 480 | + }); | |
| 481 | + } | |
| 482 | + | |
| 483 | + /** | |
| 484 | + * 请求历史媒体下载 | |
| 485 | + * | |
| 486 | + * @param device 视频设备 | |
| 487 | + * @param channelId 预览通道 | |
| 488 | + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 489 | + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 490 | + * @param downloadSpeed 下载倍速参数 | |
| 491 | + */ | |
| 492 | + @Override | |
| 493 | + public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | |
| 494 | + String startTime, String endTime, int downloadSpeed, | |
| 495 | + ZlmHttpHookSubscribe.Event hookEvent, | |
| 496 | + SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 497 | + | |
| 498 | + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); | |
| 499 | + String sdpIp; | |
| 500 | + if (!ObjectUtils.isEmpty(device.getSdpIp())) { | |
| 501 | + sdpIp = device.getSdpIp(); | |
| 502 | + }else { | |
| 503 | + sdpIp = mediaServerItem.getSdpIp(); | |
| 504 | + } | |
| 505 | + StringBuffer content = new StringBuffer(200); | |
| 506 | + content.append("v=0\r\n"); | |
| 507 | + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); | |
| 508 | + content.append("s=Download\r\n"); | |
| 509 | + content.append("u=" + channelId + ":0\r\n"); | |
| 510 | + content.append("c=IN IP4 " + sdpIp + "\r\n"); | |
| 511 | + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " " | |
| 512 | + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n"); | |
| 513 | + | |
| 514 | + String streamMode = device.getStreamMode().toUpperCase(); | |
| 515 | + | |
| 516 | + if (userSetting.isSeniorSdp()) { | |
| 517 | + if ("TCP-PASSIVE".equals(streamMode)) { | |
| 518 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 519 | + } else if ("TCP-ACTIVE".equals(streamMode)) { | |
| 520 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 521 | + } else if ("UDP".equals(streamMode)) { | |
| 522 | + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n"); | |
| 523 | + } | |
| 524 | + content.append("a=recvonly\r\n"); | |
| 525 | + content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 526 | + content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); | |
| 527 | + content.append("a=rtpmap:126 H264/90000\r\n"); | |
| 528 | + content.append("a=rtpmap:125 H264S/90000\r\n"); | |
| 529 | + content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); | |
| 530 | + content.append("a=rtpmap:99 MP4V-ES/90000\r\n"); | |
| 531 | + content.append("a=fmtp:99 profile-level-id=3\r\n"); | |
| 532 | + content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 533 | + content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 534 | + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 | |
| 535 | + content.append("a=setup:passive\r\n"); | |
| 536 | + content.append("a=connection:new\r\n"); | |
| 537 | + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 | |
| 538 | + content.append("a=setup:active\r\n"); | |
| 539 | + content.append("a=connection:new\r\n"); | |
| 540 | + } | |
| 541 | + } else { | |
| 542 | + if ("TCP-PASSIVE".equals(streamMode)) { | |
| 543 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 544 | + } else if ("TCP-ACTIVE".equals(streamMode)) { | |
| 545 | + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n"); | |
| 546 | + } else if ("UDP".equals(streamMode)) { | |
| 547 | + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n"); | |
| 548 | + } | |
| 549 | + content.append("a=recvonly\r\n"); | |
| 550 | + content.append("a=rtpmap:96 PS/90000\r\n"); | |
| 551 | + content.append("a=rtpmap:97 MPEG4/90000\r\n"); | |
| 552 | + content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 553 | + content.append("a=rtpmap:99 H265/90000\r\n"); | |
| 554 | + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 | |
| 555 | + content.append("a=setup:passive\r\n"); | |
| 556 | + content.append("a=connection:new\r\n"); | |
| 557 | + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 | |
| 558 | + content.append("a=setup:active\r\n"); | |
| 559 | + content.append("a=connection:new\r\n"); | |
| 560 | + } | |
| 561 | + } | |
| 562 | + content.append("a=downloadspeed:" + downloadSpeed + "\r\n"); | |
| 563 | + | |
| 564 | + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc | |
| 565 | + logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc()); | |
| 566 | + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); | |
| 567 | + // 添加订阅 | |
| 568 | + CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); | |
| 569 | + String callId= newCallIdHeader.getCallId(); | |
| 570 | + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> { | |
| 571 | + logger.debug("sipc 添加订阅===callId {}",callId); | |
| 572 | + hookEvent.response(mediaServerItemInUse, hookParam); | |
| 573 | + subscribe.removeSubscribe(hookSubscribe); | |
| 574 | + hookSubscribe.getContent().put("regist", false); | |
| 575 | + hookSubscribe.getContent().put("schema", "rtsp"); | |
| 576 | + // 添加流注销的订阅,注销了后向设备发送bye | |
| 577 | + subscribe.addSubscribe(hookSubscribe, | |
| 578 | + (mediaServerItemForEnd, hookParam1) -> { | |
| 579 | + logger.info("[录像]下载结束, 发送BYE"); | |
| 580 | + try { | |
| 581 | + streamByeCmd(device, channelId, ssrcInfo.getStream(), callId); | |
| 582 | + } catch (InvalidArgumentException | ParseException | SipException | | |
| 583 | + SsrcTransactionNotFoundException e) { | |
| 584 | + logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage()); | |
| 585 | + } | |
| 586 | + }); | |
| 587 | + }); | |
| 588 | + | |
| 589 | + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc()); | |
| 590 | + | |
| 591 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { | |
| 592 | + ResponseEvent responseEvent = (ResponseEvent) event.event; | |
| 593 | + SIPResponse response = (SIPResponse) responseEvent.getResponse(); | |
| 594 | + String contentString =new String(response.getRawContent()); | |
| 595 | + String ssrc = SipUtils.getSsrcFromSdp(contentString); | |
| 596 | + streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD); | |
| 597 | + okEvent.response(event); | |
| 598 | + }); | |
| 599 | + } | |
| 600 | + | |
| 601 | + /** | |
| 602 | + * 视频流停止, 不使用回调 | |
| 603 | + */ | |
| 604 | + @Override | |
| 605 | + public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException { | |
| 606 | + streamByeCmd(device, channelId, stream, callId, null); | |
| 607 | + } | |
| 608 | + | |
| 609 | + /** | |
| 610 | + * 视频流停止 | |
| 611 | + */ | |
| 612 | + @Override | |
| 613 | + public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { | |
| 614 | + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callId, stream); | |
| 615 | + if (ssrcTransaction == null) { | |
| 616 | + throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream); | |
| 617 | + } | |
| 618 | + | |
| 619 | + mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); | |
| 620 | + mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); | |
| 621 | + streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); | |
| 622 | + | |
| 623 | + Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo()); | |
| 624 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent); | |
| 625 | + } | |
| 626 | + | |
| 627 | + /** | |
| 628 | + * 语音广播 | |
| 629 | + * | |
| 630 | + * @param device 视频设备 | |
| 631 | + * @param channelId 预览通道 | |
| 632 | + */ | |
| 633 | + @Override | |
| 634 | + public void audioBroadcastCmd(Device device, String channelId) { | |
| 635 | + } | |
| 636 | + | |
| 637 | + /** | |
| 638 | + * 语音广播 | |
| 639 | + * | |
| 640 | + * @param device 视频设备 | |
| 641 | + */ | |
| 642 | + @Override | |
| 643 | + public void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException { | |
| 644 | + | |
| 645 | + StringBuffer broadcastXml = new StringBuffer(200); | |
| 646 | + String charset = device.getCharset(); | |
| 647 | + broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 648 | + broadcastXml.append("<Notify>\r\n"); | |
| 649 | + broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n"); | |
| 650 | + broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 651 | + broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n"); | |
| 652 | + broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n"); | |
| 653 | + broadcastXml.append("</Notify>\r\n"); | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 658 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); | |
| 659 | + | |
| 660 | + } | |
| 661 | + | |
| 662 | + @Override | |
| 663 | + public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 664 | + | |
| 665 | + StringBuffer broadcastXml = new StringBuffer(200); | |
| 666 | + String charset = device.getCharset(); | |
| 667 | + broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 668 | + broadcastXml.append("<Notify>\r\n"); | |
| 669 | + broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n"); | |
| 670 | + broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 671 | + broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n"); | |
| 672 | + broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n"); | |
| 673 | + broadcastXml.append("</Notify>\r\n"); | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 678 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 679 | + | |
| 680 | + } | |
| 681 | + | |
| 682 | + | |
| 683 | + /** | |
| 684 | + * 音视频录像控制 | |
| 685 | + * | |
| 686 | + * @param device 视频设备 | |
| 687 | + * @param channelId 预览通道 | |
| 688 | + * @param recordCmdStr 录像命令:Record / StopRecord | |
| 689 | + */ | |
| 690 | + @Override | |
| 691 | + public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 692 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 693 | + String charset = device.getCharset(); | |
| 694 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 695 | + cmdXml.append("<Control>\r\n"); | |
| 696 | + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 697 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 698 | + if (ObjectUtils.isEmpty(channelId)) { | |
| 699 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 700 | + } else { | |
| 701 | + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 702 | + } | |
| 703 | + cmdXml.append("<RecordCmd>" + recordCmdStr + "</RecordCmd>\r\n"); | |
| 704 | + cmdXml.append("</Control>\r\n"); | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 709 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); | |
| 710 | + } | |
| 711 | + | |
| 712 | + /** | |
| 713 | + * 远程启动控制命令 | |
| 714 | + * | |
| 715 | + * @param device 视频设备 | |
| 716 | + */ | |
| 717 | + @Override | |
| 718 | + public void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException { | |
| 719 | + | |
| 720 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 721 | + String charset = device.getCharset(); | |
| 722 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 723 | + cmdXml.append("<Control>\r\n"); | |
| 724 | + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 725 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 726 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 727 | + cmdXml.append("<TeleBoot>Boot</TeleBoot>\r\n"); | |
| 728 | + cmdXml.append("</Control>\r\n"); | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 733 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); | |
| 734 | + } | |
| 735 | + | |
| 736 | + /** | |
| 737 | + * 报警布防/撤防命令 | |
| 738 | + * | |
| 739 | + * @param device 视频设备 | |
| 740 | + * @param guardCmdStr "SetGuard"/"ResetGuard" | |
| 741 | + */ | |
| 742 | + @Override | |
| 743 | + public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 744 | + | |
| 745 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 746 | + String charset = device.getCharset(); | |
| 747 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 748 | + cmdXml.append("<Control>\r\n"); | |
| 749 | + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 750 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 751 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 752 | + cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n"); | |
| 753 | + cmdXml.append("</Control>\r\n"); | |
| 754 | + | |
| 755 | + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 756 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); | |
| 757 | + } | |
| 758 | + | |
| 759 | + /** | |
| 760 | + * 报警复位命令 | |
| 761 | + * | |
| 762 | + * @param device 视频设备 | |
| 763 | + */ | |
| 764 | + @Override | |
| 765 | + public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 766 | + | |
| 767 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 768 | + String charset = device.getCharset(); | |
| 769 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 770 | + cmdXml.append("<Control>\r\n"); | |
| 771 | + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 772 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 773 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 774 | + cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n"); | |
| 775 | + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { | |
| 776 | + cmdXml.append("<Info>\r\n"); | |
| 777 | + } | |
| 778 | + if (!ObjectUtils.isEmpty(alarmMethod)) { | |
| 779 | + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n"); | |
| 780 | + } | |
| 781 | + if (!ObjectUtils.isEmpty(alarmType)) { | |
| 782 | + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n"); | |
| 783 | + } | |
| 784 | + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { | |
| 785 | + cmdXml.append("</Info>\r\n"); | |
| 786 | + } | |
| 787 | + cmdXml.append("</Control>\r\n"); | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 792 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); | |
| 793 | + } | |
| 794 | + | |
| 795 | + /** | |
| 796 | + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 | |
| 797 | + * | |
| 798 | + * @param device 视频设备 | |
| 799 | + * @param channelId 预览通道 | |
| 800 | + */ | |
| 801 | + @Override | |
| 802 | + public void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException { | |
| 803 | + | |
| 804 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 805 | + String charset = device.getCharset(); | |
| 806 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 807 | + cmdXml.append("<Control>\r\n"); | |
| 808 | + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 809 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 810 | + if (ObjectUtils.isEmpty(channelId)) { | |
| 811 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 812 | + } else { | |
| 813 | + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 814 | + } | |
| 815 | + cmdXml.append("<IFameCmd>Send</IFameCmd>\r\n"); | |
| 816 | + cmdXml.append("</Control>\r\n"); | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 821 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); | |
| 822 | + } | |
| 823 | + | |
| 824 | + /** | |
| 825 | + * 看守位控制命令 | |
| 826 | + * | |
| 827 | + * @param device 视频设备 | |
| 828 | + * @param channelId 通道id,非通道则是设备本身 | |
| 829 | + * @param enabled 看守位使能:1 = 开启,0 = 关闭 | |
| 830 | + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) | |
| 831 | + * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 | |
| 832 | + */ | |
| 833 | + @Override | |
| 834 | + public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 835 | + | |
| 836 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 837 | + String charset = device.getCharset(); | |
| 838 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 839 | + cmdXml.append("<Control>\r\n"); | |
| 840 | + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 841 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 842 | + if (ObjectUtils.isEmpty(channelId)) { | |
| 843 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 844 | + } else { | |
| 845 | + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 846 | + } | |
| 847 | + cmdXml.append("<HomePosition>\r\n"); | |
| 848 | + if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) { | |
| 849 | + cmdXml.append("<Enabled>1</Enabled>\r\n"); | |
| 850 | + if (NumericUtil.isInteger(resetTime)) { | |
| 851 | + cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n"); | |
| 852 | + } else { | |
| 853 | + cmdXml.append("<ResetTime>0</ResetTime>\r\n"); | |
| 854 | + } | |
| 855 | + if (NumericUtil.isInteger(presetIndex)) { | |
| 856 | + cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n"); | |
| 857 | + } else { | |
| 858 | + cmdXml.append("<PresetIndex>0</PresetIndex>\r\n"); | |
| 859 | + } | |
| 860 | + } else { | |
| 861 | + cmdXml.append("<Enabled>0</Enabled>\r\n"); | |
| 862 | + } | |
| 863 | + cmdXml.append("</HomePosition>\r\n"); | |
| 864 | + cmdXml.append("</Control>\r\n"); | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 869 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); | |
| 870 | + } | |
| 871 | + | |
| 872 | + /** | |
| 873 | + * 设备配置命令 | |
| 874 | + * | |
| 875 | + * @param device 视频设备 | |
| 876 | + */ | |
| 877 | + @Override | |
| 878 | + public void deviceConfigCmd(Device device) { | |
| 879 | + // TODO Auto-generated method stub | |
| 880 | + } | |
| 881 | + | |
| 882 | + /** | |
| 883 | + * 设备配置命令:basicParam | |
| 884 | + * | |
| 885 | + * @param device 视频设备 | |
| 886 | + * @param channelId 通道编码(可选) | |
| 887 | + * @param name 设备/通道名称(可选) | |
| 888 | + * @param expiration 注册过期时间(可选) | |
| 889 | + * @param heartBeatInterval 心跳间隔时间(可选) | |
| 890 | + * @param heartBeatCount 心跳超时次数(可选) | |
| 891 | + */ | |
| 892 | + @Override | |
| 893 | + public void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, | |
| 894 | + String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 895 | + | |
| 896 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 897 | + String charset = device.getCharset(); | |
| 898 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 899 | + cmdXml.append("<Control>\r\n"); | |
| 900 | + cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n"); | |
| 901 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 902 | + if (ObjectUtils.isEmpty(channelId)) { | |
| 903 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 904 | + } else { | |
| 905 | + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 906 | + } | |
| 907 | + cmdXml.append("<BasicParam>\r\n"); | |
| 908 | + if (!ObjectUtils.isEmpty(name)) { | |
| 909 | + cmdXml.append("<Name>" + name + "</Name>\r\n"); | |
| 910 | + } | |
| 911 | + if (NumericUtil.isInteger(expiration)) { | |
| 912 | + if (Integer.valueOf(expiration) > 0) { | |
| 913 | + cmdXml.append("<Expiration>" + expiration + "</Expiration>\r\n"); | |
| 914 | + } | |
| 915 | + } | |
| 916 | + if (NumericUtil.isInteger(heartBeatInterval)) { | |
| 917 | + if (Integer.valueOf(heartBeatInterval) > 0) { | |
| 918 | + cmdXml.append("<HeartBeatInterval>" + heartBeatInterval + "</HeartBeatInterval>\r\n"); | |
| 919 | + } | |
| 920 | + } | |
| 921 | + if (NumericUtil.isInteger(heartBeatCount)) { | |
| 922 | + if (Integer.valueOf(heartBeatCount) > 0) { | |
| 923 | + cmdXml.append("<HeartBeatCount>" + heartBeatCount + "</HeartBeatCount>\r\n"); | |
| 924 | + } | |
| 925 | + } | |
| 926 | + cmdXml.append("</BasicParam>\r\n"); | |
| 927 | + cmdXml.append("</Control>\r\n"); | |
| 928 | + | |
| 929 | + | |
| 930 | + | |
| 931 | + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 932 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 933 | + } | |
| 934 | + | |
| 935 | + /** | |
| 936 | + * 查询设备状态 | |
| 937 | + * | |
| 938 | + * @param device 视频设备 | |
| 939 | + */ | |
| 940 | + @Override | |
| 941 | + public void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 942 | + | |
| 943 | + String charset = device.getCharset(); | |
| 944 | + StringBuffer catalogXml = new StringBuffer(200); | |
| 945 | + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 946 | + catalogXml.append("<Query>\r\n"); | |
| 947 | + catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n"); | |
| 948 | + catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 949 | + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 950 | + catalogXml.append("</Query>\r\n"); | |
| 951 | + | |
| 952 | + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 953 | + | |
| 954 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 955 | + } | |
| 956 | + | |
| 957 | + /** | |
| 958 | + * 查询设备信息 | |
| 959 | + * | |
| 960 | + * @param device 视频设备 | |
| 961 | + */ | |
| 962 | + @Override | |
| 963 | + public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException { | |
| 964 | + | |
| 965 | + StringBuffer catalogXml = new StringBuffer(200); | |
| 966 | + String charset = device.getCharset(); | |
| 967 | + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 968 | + catalogXml.append("<Query>\r\n"); | |
| 969 | + catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n"); | |
| 970 | + catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 971 | + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 972 | + catalogXml.append("</Query>\r\n"); | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 977 | + | |
| 978 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); | |
| 979 | + | |
| 980 | + } | |
| 981 | + | |
| 982 | + /** | |
| 983 | + * 查询目录列表 | |
| 984 | + * | |
| 985 | + * @param device 视频设备 | |
| 986 | + */ | |
| 987 | + @Override | |
| 988 | + public void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException { | |
| 989 | + | |
| 990 | + StringBuffer catalogXml = new StringBuffer(200); | |
| 991 | + String charset = device.getCharset(); | |
| 992 | + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 993 | + catalogXml.append("<Query>\r\n"); | |
| 994 | + catalogXml.append(" <CmdType>Catalog</CmdType>\r\n"); | |
| 995 | + catalogXml.append(" <SN>" + sn + "</SN>\r\n"); | |
| 996 | + catalogXml.append(" <DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 997 | + catalogXml.append("</Query>\r\n"); | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1002 | + | |
| 1003 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 1004 | + } | |
| 1005 | + | |
| 1006 | + /** | |
| 1007 | + * 查询录像信息 | |
| 1008 | + * | |
| 1009 | + * @param device 视频设备 | |
| 1010 | + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 1011 | + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | |
| 1012 | + */ | |
| 1013 | + @Override | |
| 1014 | + 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 { | |
| 1015 | + if (secrecy == null) { | |
| 1016 | + secrecy = 0; | |
| 1017 | + } | |
| 1018 | + if (type == null) { | |
| 1019 | + type = "all"; | |
| 1020 | + } | |
| 1021 | + | |
| 1022 | + StringBuffer recordInfoXml = new StringBuffer(200); | |
| 1023 | + String charset = device.getCharset(); | |
| 1024 | + recordInfoXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1025 | + recordInfoXml.append("<Query>\r\n"); | |
| 1026 | + recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n"); | |
| 1027 | + recordInfoXml.append("<SN>" + sn + "</SN>\r\n"); | |
| 1028 | + recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 1029 | + if (startTime != null) { | |
| 1030 | + recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n"); | |
| 1031 | + } | |
| 1032 | + if (endTime != null) { | |
| 1033 | + recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n"); | |
| 1034 | + } | |
| 1035 | + if (secrecy != null) { | |
| 1036 | + recordInfoXml.append("<Secrecy> " + secrecy + " </Secrecy>\r\n"); | |
| 1037 | + } | |
| 1038 | + if (type != null) { | |
| 1039 | + // 大华NVR要求必须增加一个值为all的文本元素节点Type | |
| 1040 | + recordInfoXml.append("<Type>" + type + "</Type>\r\n"); | |
| 1041 | + } | |
| 1042 | + recordInfoXml.append("</Query>\r\n"); | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), | |
| 1047 | + SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1048 | + | |
| 1049 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); | |
| 1050 | + } | |
| 1051 | + | |
| 1052 | + /** | |
| 1053 | + * 查询报警信息 | |
| 1054 | + * | |
| 1055 | + * @param device 视频设备 | |
| 1056 | + * @param startPriority 报警起始级别(可选) | |
| 1057 | + * @param endPriority 报警终止级别(可选) | |
| 1058 | + * @param alarmMethod 报警方式条件(可选) | |
| 1059 | + * @param alarmType 报警类型 | |
| 1060 | + * @param startTime 报警发生起始时间(可选) | |
| 1061 | + * @param endTime 报警发生终止时间(可选) | |
| 1062 | + * @return true = 命令发送成功 | |
| 1063 | + */ | |
| 1064 | + @Override | |
| 1065 | + public void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, | |
| 1066 | + String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1067 | + | |
| 1068 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 1069 | + String charset = device.getCharset(); | |
| 1070 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1071 | + cmdXml.append("<Query>\r\n"); | |
| 1072 | + cmdXml.append("<CmdType>Alarm</CmdType>\r\n"); | |
| 1073 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1074 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1075 | + if (!ObjectUtils.isEmpty(startPriority)) { | |
| 1076 | + cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n"); | |
| 1077 | + } | |
| 1078 | + if (!ObjectUtils.isEmpty(endPriority)) { | |
| 1079 | + cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n"); | |
| 1080 | + } | |
| 1081 | + if (!ObjectUtils.isEmpty(alarmMethod)) { | |
| 1082 | + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n"); | |
| 1083 | + } | |
| 1084 | + if (!ObjectUtils.isEmpty(alarmType)) { | |
| 1085 | + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n"); | |
| 1086 | + } | |
| 1087 | + if (!ObjectUtils.isEmpty(startTime)) { | |
| 1088 | + cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n"); | |
| 1089 | + } | |
| 1090 | + if (!ObjectUtils.isEmpty(endTime)) { | |
| 1091 | + cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n"); | |
| 1092 | + } | |
| 1093 | + cmdXml.append("</Query>\r\n"); | |
| 1094 | + | |
| 1095 | + | |
| 1096 | + | |
| 1097 | + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1098 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 1099 | + } | |
| 1100 | + | |
| 1101 | + /** | |
| 1102 | + * 查询设备配置 | |
| 1103 | + * | |
| 1104 | + * @param device 视频设备 | |
| 1105 | + * @param channelId 通道编码(可选) | |
| 1106 | + * @param configType 配置类型: | |
| 1107 | + */ | |
| 1108 | + @Override | |
| 1109 | + public void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1110 | + | |
| 1111 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 1112 | + String charset = device.getCharset(); | |
| 1113 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1114 | + cmdXml.append("<Query>\r\n"); | |
| 1115 | + cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n"); | |
| 1116 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1117 | + if (ObjectUtils.isEmpty(channelId)) { | |
| 1118 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1119 | + } else { | |
| 1120 | + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 1121 | + } | |
| 1122 | + cmdXml.append("<ConfigType>" + configType + "</ConfigType>\r\n"); | |
| 1123 | + cmdXml.append("</Query>\r\n"); | |
| 1124 | + | |
| 1125 | + | |
| 1126 | + | |
| 1127 | + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1128 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 1129 | + } | |
| 1130 | + | |
| 1131 | + /** | |
| 1132 | + * 查询设备预置位置 | |
| 1133 | + * | |
| 1134 | + * @param device 视频设备 | |
| 1135 | + */ | |
| 1136 | + @Override | |
| 1137 | + public void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1138 | + | |
| 1139 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 1140 | + String charset = device.getCharset(); | |
| 1141 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1142 | + cmdXml.append("<Query>\r\n"); | |
| 1143 | + cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n"); | |
| 1144 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1145 | + if (ObjectUtils.isEmpty(channelId)) { | |
| 1146 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1147 | + } else { | |
| 1148 | + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 1149 | + } | |
| 1150 | + cmdXml.append("</Query>\r\n"); | |
| 1151 | + | |
| 1152 | + | |
| 1153 | + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1154 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 1155 | + } | |
| 1156 | + | |
| 1157 | + /** | |
| 1158 | + * 查询移动设备位置数据 | |
| 1159 | + * | |
| 1160 | + * @param device 视频设备 | |
| 1161 | + */ | |
| 1162 | + @Override | |
| 1163 | + public void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1164 | + | |
| 1165 | + StringBuffer mobilePostitionXml = new StringBuffer(200); | |
| 1166 | + String charset = device.getCharset(); | |
| 1167 | + mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1168 | + mobilePostitionXml.append("<Query>\r\n"); | |
| 1169 | + mobilePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n"); | |
| 1170 | + mobilePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1171 | + mobilePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1172 | + mobilePostitionXml.append("<Interval>60</Interval>\r\n"); | |
| 1173 | + mobilePostitionXml.append("</Query>\r\n"); | |
| 1174 | + | |
| 1175 | + | |
| 1176 | + | |
| 1177 | + Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1178 | + | |
| 1179 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); | |
| 1180 | + | |
| 1181 | + } | |
| 1182 | + | |
| 1183 | + /** | |
| 1184 | + * 订阅、取消订阅移动位置 | |
| 1185 | + * | |
| 1186 | + * @param device 视频设备 | |
| 1187 | + * @return true = 命令发送成功 | |
| 1188 | + */ | |
| 1189 | + @Override | |
| 1190 | + public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1191 | + | |
| 1192 | + StringBuffer subscribePostitionXml = new StringBuffer(200); | |
| 1193 | + String charset = device.getCharset(); | |
| 1194 | + subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1195 | + subscribePostitionXml.append("<Query>\r\n"); | |
| 1196 | + subscribePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n"); | |
| 1197 | + subscribePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1198 | + subscribePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1199 | + if (device.getSubscribeCycleForMobilePosition() > 0) { | |
| 1200 | + subscribePostitionXml.append("<Interval>" + device.getMobilePositionSubmissionInterval() + "</Interval>\r\n"); | |
| 1201 | + } | |
| 1202 | + subscribePostitionXml.append("</Query>\r\n"); | |
| 1203 | + | |
| 1204 | + CallIdHeader callIdHeader; | |
| 1205 | + | |
| 1206 | + if (requestOld != null) { | |
| 1207 | + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); | |
| 1208 | + } else { | |
| 1209 | + callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); | |
| 1210 | + } | |
| 1211 | + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence",callIdHeader); //Position;id=" + tm.substring(tm.length() - 4)); | |
| 1212 | + | |
| 1213 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); | |
| 1214 | + return request; | |
| 1215 | + } | |
| 1216 | + | |
| 1217 | + /** | |
| 1218 | + * 订阅、取消订阅报警信息 | |
| 1219 | + * | |
| 1220 | + * @param device 视频设备 | |
| 1221 | + * @param expires 订阅过期时间(0 = 取消订阅) | |
| 1222 | + * @param startPriority 报警起始级别(可选) | |
| 1223 | + * @param endPriority 报警终止级别(可选) | |
| 1224 | + * @param alarmMethod 报警方式条件(可选) | |
| 1225 | + * @param alarmType 报警类型 | |
| 1226 | + * @param startTime 报警发生起始时间(可选) | |
| 1227 | + * @param endTime 报警发生终止时间(可选) | |
| 1228 | + * @return true = 命令发送成功 | |
| 1229 | + */ | |
| 1230 | + @Override | |
| 1231 | + public void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException { | |
| 1232 | + | |
| 1233 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 1234 | + String charset = device.getCharset(); | |
| 1235 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1236 | + cmdXml.append("<Query>\r\n"); | |
| 1237 | + cmdXml.append("<CmdType>Alarm</CmdType>\r\n"); | |
| 1238 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1239 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1240 | + if (!ObjectUtils.isEmpty(startPriority)) { | |
| 1241 | + cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n"); | |
| 1242 | + } | |
| 1243 | + if (!ObjectUtils.isEmpty(endPriority)) { | |
| 1244 | + cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n"); | |
| 1245 | + } | |
| 1246 | + if (!ObjectUtils.isEmpty(alarmMethod)) { | |
| 1247 | + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n"); | |
| 1248 | + } | |
| 1249 | + if (!ObjectUtils.isEmpty(startTime)) { | |
| 1250 | + cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n"); | |
| 1251 | + } | |
| 1252 | + if (!ObjectUtils.isEmpty(endTime)) { | |
| 1253 | + cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n"); | |
| 1254 | + } | |
| 1255 | + cmdXml.append("</Query>\r\n"); | |
| 1256 | + | |
| 1257 | + | |
| 1258 | + | |
| 1259 | + Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence",sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1260 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); | |
| 1261 | + | |
| 1262 | + } | |
| 1263 | + | |
| 1264 | + @Override | |
| 1265 | + public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | |
| 1266 | + | |
| 1267 | + StringBuffer cmdXml = new StringBuffer(200); | |
| 1268 | + String charset = device.getCharset(); | |
| 1269 | + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1270 | + cmdXml.append("<Query>\r\n"); | |
| 1271 | + cmdXml.append("<CmdType>Catalog</CmdType>\r\n"); | |
| 1272 | + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1273 | + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1274 | + cmdXml.append("</Query>\r\n"); | |
| 1275 | + | |
| 1276 | + CallIdHeader callIdHeader; | |
| 1277 | + | |
| 1278 | + if (requestOld != null) { | |
| 1279 | + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); | |
| 1280 | + } else { | |
| 1281 | + callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); | |
| 1282 | + } | |
| 1283 | + | |
| 1284 | + // 有效时间默认为60秒以上 | |
| 1285 | + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog", | |
| 1286 | + callIdHeader); | |
| 1287 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); | |
| 1288 | + return request; | |
| 1289 | + } | |
| 1290 | + | |
| 1291 | + @Override | |
| 1292 | + public void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException { | |
| 1293 | + | |
| 1294 | + StringBuffer dragXml = new StringBuffer(200); | |
| 1295 | + String charset = device.getCharset(); | |
| 1296 | + dragXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); | |
| 1297 | + dragXml.append("<Control>\r\n"); | |
| 1298 | + dragXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 1299 | + dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1300 | + if (ObjectUtils.isEmpty(channelId)) { | |
| 1301 | + dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | |
| 1302 | + } else { | |
| 1303 | + dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 1304 | + } | |
| 1305 | + dragXml.append(cmdString); | |
| 1306 | + dragXml.append("</Control>\r\n"); | |
| 1307 | + | |
| 1308 | + Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1309 | + logger.debug("拉框信令: " + request.toString()); | |
| 1310 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); | |
| 1311 | + } | |
| 1312 | + | |
| 1313 | + | |
| 1314 | + | |
| 1315 | + | |
| 1316 | + | |
| 1317 | + /** | |
| 1318 | + * 回放暂停 | |
| 1319 | + */ | |
| 1320 | + @Override | |
| 1321 | + public void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException { | |
| 1322 | + StringBuffer content = new StringBuffer(200); | |
| 1323 | + content.append("PAUSE RTSP/1.0\r\n"); | |
| 1324 | + content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1325 | + content.append("PauseTime: now\r\n"); | |
| 1326 | + | |
| 1327 | + playbackControlCmd(device, streamInfo, content.toString(), null, null); | |
| 1328 | + } | |
| 1329 | + | |
| 1330 | + | |
| 1331 | + /** | |
| 1332 | + * 回放恢复 | |
| 1333 | + */ | |
| 1334 | + @Override | |
| 1335 | + public void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException { | |
| 1336 | + StringBuffer content = new StringBuffer(200); | |
| 1337 | + content.append("PLAY RTSP/1.0\r\n"); | |
| 1338 | + content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1339 | + content.append("Range: npt=now-\r\n"); | |
| 1340 | + | |
| 1341 | + playbackControlCmd(device, streamInfo, content.toString(), null, null); | |
| 1342 | + } | |
| 1343 | + | |
| 1344 | + /** | |
| 1345 | + * 回放拖动播放 | |
| 1346 | + */ | |
| 1347 | + @Override | |
| 1348 | + public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException { | |
| 1349 | + StringBuffer content = new StringBuffer(200); | |
| 1350 | + content.append("PLAY RTSP/1.0\r\n"); | |
| 1351 | + content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1352 | + content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n"); | |
| 1353 | + | |
| 1354 | + playbackControlCmd(device, streamInfo, content.toString(), null, null); | |
| 1355 | + } | |
| 1356 | + | |
| 1357 | + /** | |
| 1358 | + * 回放倍速播放 | |
| 1359 | + */ | |
| 1360 | + @Override | |
| 1361 | + public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException { | |
| 1362 | + StringBuffer content = new StringBuffer(200); | |
| 1363 | + content.append("PLAY RTSP/1.0\r\n"); | |
| 1364 | + content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1365 | + content.append("Scale: " + String.format("%.6f", speed) + "\r\n"); | |
| 1366 | + | |
| 1367 | + playbackControlCmd(device, streamInfo, content.toString(), null, null); | |
| 1368 | + } | |
| 1369 | + | |
| 1370 | + private int getInfoCseq() { | |
| 1371 | + return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8)); | |
| 1372 | + } | |
| 1373 | + | |
| 1374 | + @Override | |
| 1375 | + public void playbackControlCmd(Device device, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException { | |
| 1376 | + | |
| 1377 | + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), streamInfo.getChannelId(), null, streamInfo.getStream()); | |
| 1378 | + if (ssrcTransaction == null) { | |
| 1379 | + logger.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); | |
| 1380 | + return; | |
| 1381 | + } | |
| 1382 | + | |
| 1383 | + SIPRequest request = headerProvider.createInfoRequest(device, streamInfo.getChannelId(), content.toString(), ssrcTransaction.getSipTransactionInfo()); | |
| 1384 | + if (request == null) { | |
| 1385 | + logger.info("[回放控制]构建Request信息失败,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); | |
| 1386 | + return; | |
| 1387 | + } | |
| 1388 | + | |
| 1389 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); | |
| 1390 | + } | |
| 1391 | + | |
| 1392 | + @Override | |
| 1393 | + public void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException { | |
| 1394 | + if (device == null) { | |
| 1395 | + return; | |
| 1396 | + } | |
| 1397 | + logger.info("[发送报警通知]设备: {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(), | |
| 1398 | + deviceAlarm.getLongitude(), deviceAlarm.getLatitude()); | |
| 1399 | + | |
| 1400 | + String characterSet = device.getCharset(); | |
| 1401 | + StringBuffer deviceStatusXml = new StringBuffer(600); | |
| 1402 | + deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n"); | |
| 1403 | + deviceStatusXml.append("<Notify>\r\n"); | |
| 1404 | + deviceStatusXml.append("<CmdType>Alarm</CmdType>\r\n"); | |
| 1405 | + deviceStatusXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); | |
| 1406 | + deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n"); | |
| 1407 | + deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n"); | |
| 1408 | + deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n"); | |
| 1409 | + deviceStatusXml.append("<AlarmTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(deviceAlarm.getAlarmTime()) + "</AlarmTime>\r\n"); | |
| 1410 | + deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n"); | |
| 1411 | + deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n"); | |
| 1412 | + deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n"); | |
| 1413 | + deviceStatusXml.append("<info>\r\n"); | |
| 1414 | + deviceStatusXml.append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n"); | |
| 1415 | + deviceStatusXml.append("</info>\r\n"); | |
| 1416 | + deviceStatusXml.append("</Notify>\r\n"); | |
| 1417 | + | |
| 1418 | + | |
| 1419 | + Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | |
| 1420 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); | |
| 1421 | + | |
| 1422 | + | |
| 1423 | + } | |
| 1424 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/ISIPRequestProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/CancelRequestProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
100644 → 100755
| ... | ... | @@ -18,10 +18,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; |
| 18 | 18 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| 19 | 19 | import com.genersoft.iot.vmp.media.zlm.dto.*; |
| 20 | 20 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; |
| 21 | -import com.genersoft.iot.vmp.service.IMediaServerService; | |
| 22 | -import com.genersoft.iot.vmp.service.IPlayService; | |
| 23 | -import com.genersoft.iot.vmp.service.IStreamProxyService; | |
| 24 | -import com.genersoft.iot.vmp.service.IStreamPushService; | |
| 21 | +import com.genersoft.iot.vmp.service.*; | |
| 25 | 22 | import com.genersoft.iot.vmp.service.bean.ErrorCallback; |
| 26 | 23 | import com.genersoft.iot.vmp.service.bean.InviteErrorCode; |
| 27 | 24 | import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; |
| ... | ... | @@ -80,6 +77,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 80 | 77 | private IRedisCatchStorage redisCatchStorage; |
| 81 | 78 | |
| 82 | 79 | @Autowired |
| 80 | + private IInviteStreamService inviteStreamService; | |
| 81 | + | |
| 82 | + @Autowired | |
| 83 | 83 | private SSRCFactory ssrcFactory; |
| 84 | 84 | |
| 85 | 85 | @Autowired |
| ... | ... | @@ -479,13 +479,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 479 | 479 | errorEvent.run(code, msg, data); |
| 480 | 480 | } |
| 481 | 481 | }); |
| 482 | - }else if ("Download".equalsIgnoreCase(sessionName)) { | |
| 482 | + } else if ("Download".equalsIgnoreCase(sessionName)) { | |
| 483 | 483 | // 获取指定的下载速度 |
| 484 | 484 | Vector sdpMediaDescriptions = sdp.getMediaDescriptions(true); |
| 485 | 485 | MediaDescription mediaDescription = null; |
| 486 | 486 | String downloadSpeed = "1"; |
| 487 | 487 | if (sdpMediaDescriptions.size() > 0) { |
| 488 | - mediaDescription = (MediaDescription)sdpMediaDescriptions.get(0); | |
| 488 | + mediaDescription = (MediaDescription) sdpMediaDescriptions.get(0); | |
| 489 | 489 | } |
| 490 | 490 | if (mediaDescription != null) { |
| 491 | 491 | downloadSpeed = mediaDescription.getAttribute("downloadspeed"); |
| ... | ... | @@ -499,26 +499,26 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 499 | 499 | playService.download(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start), |
| 500 | 500 | DateUtil.formatter.format(end), Integer.parseInt(downloadSpeed), |
| 501 | 501 | (code, msg, data) -> { |
| 502 | - if (code == InviteErrorCode.SUCCESS.getCode()){ | |
| 502 | + if (code == InviteErrorCode.SUCCESS.getCode()) { | |
| 503 | 503 | hookEvent.run(code, msg, data); |
| 504 | - }else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()){ | |
| 504 | + } else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()) { | |
| 505 | 505 | logger.info("[录像下载]超时, 用户:{}, 通道:{}", username, channelId); |
| 506 | 506 | redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); |
| 507 | 507 | errorEvent.run(code, msg, data); |
| 508 | - }else { | |
| 508 | + } else { | |
| 509 | 509 | errorEvent.run(code, msg, data); |
| 510 | 510 | } |
| 511 | 511 | }); |
| 512 | - }else { | |
| 512 | + } else { | |
| 513 | 513 | |
| 514 | 514 | SSRCInfo ssrcInfo = playService.play(mediaServerItem, device.getDeviceId(), channelId, ssrc, ((code, msg, data) -> { |
| 515 | - if (code == InviteErrorCode.SUCCESS.getCode()){ | |
| 515 | + if (code == InviteErrorCode.SUCCESS.getCode()) { | |
| 516 | 516 | hookEvent.run(code, msg, data); |
| 517 | - }else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()){ | |
| 517 | + } else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()) { | |
| 518 | 518 | logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId); |
| 519 | 519 | redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); |
| 520 | 520 | errorEvent.run(code, msg, data); |
| 521 | - }else { | |
| 521 | + } else { | |
| 522 | 522 | errorEvent.run(code, msg, data); |
| 523 | 523 | } |
| 524 | 524 | })); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.common.InviteInfo; | |
| 4 | -import com.genersoft.iot.vmp.common.InviteSessionType; | |
| 5 | -import com.genersoft.iot.vmp.gb28181.bean.*; | |
| 6 | -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | |
| 7 | -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 8 | -import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; | |
| 9 | -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | |
| 10 | -import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; | |
| 11 | -import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; | |
| 12 | -import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | |
| 13 | -import com.genersoft.iot.vmp.service.IInviteStreamService; | |
| 14 | -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 15 | -import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | |
| 16 | -import gov.nist.javax.sip.message.SIPRequest; | |
| 17 | -import org.slf4j.Logger; | |
| 18 | -import org.slf4j.LoggerFactory; | |
| 19 | -import org.springframework.beans.factory.InitializingBean; | |
| 20 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 21 | -import org.springframework.stereotype.Component; | |
| 22 | - | |
| 23 | -import javax.sip.InvalidArgumentException; | |
| 24 | -import javax.sip.RequestEvent; | |
| 25 | -import javax.sip.SipException; | |
| 26 | -import javax.sip.header.CallIdHeader; | |
| 27 | -import javax.sip.header.ContentTypeHeader; | |
| 28 | -import javax.sip.message.Response; | |
| 29 | -import java.text.ParseException; | |
| 30 | - | |
| 31 | -@Component | |
| 32 | -public class InfoRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { | |
| 33 | - | |
| 34 | - private final static Logger logger = LoggerFactory.getLogger(InfoRequestProcessor.class); | |
| 35 | - | |
| 36 | - private final String method = "INFO"; | |
| 37 | - | |
| 38 | - @Autowired | |
| 39 | - private SIPProcessorObserver sipProcessorObserver; | |
| 40 | - | |
| 41 | - @Autowired | |
| 42 | - private IVideoManagerStorage storage; | |
| 43 | - | |
| 44 | - @Autowired | |
| 45 | - private SipSubscribe sipSubscribe; | |
| 46 | - | |
| 47 | - @Autowired | |
| 48 | - private IRedisCatchStorage redisCatchStorage; | |
| 49 | - | |
| 50 | - @Autowired | |
| 51 | - private IInviteStreamService inviteStreamService; | |
| 52 | - | |
| 53 | - @Autowired | |
| 54 | - private IVideoManagerStorage storager; | |
| 55 | - | |
| 56 | - @Autowired | |
| 57 | - private SIPCommander cmder; | |
| 58 | - | |
| 59 | - @Autowired | |
| 60 | - private VideoStreamSessionManager sessionManager; | |
| 61 | - | |
| 62 | - @Override | |
| 63 | - public void afterPropertiesSet() throws Exception { | |
| 64 | - // 添加消息处理的订阅 | |
| 65 | - sipProcessorObserver.addRequestProcessor(method, this); | |
| 66 | - } | |
| 67 | - | |
| 68 | - @Override | |
| 69 | - public void process(RequestEvent evt) { | |
| 70 | - logger.debug("接收到消息:" + evt.getRequest()); | |
| 71 | - SIPRequest request = (SIPRequest) evt.getRequest(); | |
| 72 | - String deviceId = SipUtils.getUserIdFromFromHeader(request); | |
| 73 | - CallIdHeader callIdHeader = request.getCallIdHeader(); | |
| 74 | - // 先从会话内查找 | |
| 75 | - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); | |
| 76 | - | |
| 77 | - // 兼容海康 媒体通知 消息from字段不是设备ID的问题 | |
| 78 | - if (ssrcTransaction != null) { | |
| 79 | - deviceId = ssrcTransaction.getDeviceId(); | |
| 80 | - } | |
| 81 | - // 查询设备是否存在 | |
| 82 | - Device device = redisCatchStorage.getDevice(deviceId); | |
| 83 | - // 查询上级平台是否存在 | |
| 84 | - ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId); | |
| 85 | - try { | |
| 86 | - if (device != null && parentPlatform != null) { | |
| 87 | - logger.warn("[重复]平台与设备编号重复:{}", deviceId); | |
| 88 | - String hostAddress = request.getRemoteAddress().getHostAddress(); | |
| 89 | - int remotePort = request.getRemotePort(); | |
| 90 | - if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) { | |
| 91 | - parentPlatform = null; | |
| 92 | - }else { | |
| 93 | - device = null; | |
| 94 | - } | |
| 95 | - } | |
| 96 | - if (device == null && parentPlatform == null) { | |
| 97 | - // 不存在则回复404 | |
| 98 | - responseAck(request, Response.NOT_FOUND, "device "+ deviceId +" not found"); | |
| 99 | - logger.warn("[设备未找到 ]: {}", deviceId); | |
| 100 | - if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){ | |
| 101 | - DeviceNotFoundEvent deviceNotFoundEvent = new DeviceNotFoundEvent(evt.getDialog()); | |
| 102 | - deviceNotFoundEvent.setCallId(callIdHeader.getCallId()); | |
| 103 | - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent); | |
| 104 | - sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult); | |
| 105 | - }; | |
| 106 | - }else { | |
| 107 | - ContentTypeHeader header = (ContentTypeHeader)evt.getRequest().getHeader(ContentTypeHeader.NAME); | |
| 108 | - String contentType = header.getContentType(); | |
| 109 | - String contentSubType = header.getContentSubType(); | |
| 110 | - if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) { | |
| 111 | - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId()); | |
| 112 | - String streamId = sendRtpItem.getStreamId(); | |
| 113 | - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId); | |
| 114 | - if (null == inviteInfo) { | |
| 115 | - responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found"); | |
| 116 | - return; | |
| 117 | - } | |
| 118 | - Device device1 = storager.queryVideoDevice(inviteInfo.getDeviceId()); | |
| 119 | - if (inviteInfo.getStreamInfo() != null) { | |
| 120 | - cmder.playbackControlCmd(device1,inviteInfo.getStreamInfo(),new String(evt.getRequest().getRawContent()),eventResult -> { | |
| 121 | - // 失败的回复 | |
| 122 | - try { | |
| 123 | - responseAck(request, eventResult.statusCode, eventResult.msg); | |
| 124 | - } catch (SipException | InvalidArgumentException | ParseException e) { | |
| 125 | - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage()); | |
| 126 | - } | |
| 127 | - }, eventResult -> { | |
| 128 | - // 成功的回复 | |
| 129 | - try { | |
| 130 | - responseAck(request, eventResult.statusCode); | |
| 131 | - } catch (SipException | InvalidArgumentException | ParseException e) { | |
| 132 | - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage()); | |
| 133 | - } | |
| 134 | - }); | |
| 135 | - } | |
| 136 | - | |
| 137 | - } | |
| 138 | - } | |
| 139 | - } catch (SipException e) { | |
| 140 | - logger.warn("SIP 回复错误", e); | |
| 141 | - } catch (InvalidArgumentException e) { | |
| 142 | - logger.warn("参数无效", e); | |
| 143 | - } catch (ParseException e) { | |
| 144 | - logger.warn("SIP回复时解析异常", e); | |
| 145 | - } | |
| 146 | - } | |
| 147 | - | |
| 148 | - | |
| 149 | -} | |
| 1 | +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.common.InviteInfo; | |
| 4 | +import com.genersoft.iot.vmp.common.InviteSessionType; | |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.*; | |
| 6 | +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | |
| 7 | +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; | |
| 9 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | |
| 10 | +import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; | |
| 11 | +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; | |
| 12 | +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | |
| 13 | +import com.genersoft.iot.vmp.service.IInviteStreamService; | |
| 14 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 15 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | |
| 16 | +import gov.nist.javax.sip.message.SIPRequest; | |
| 17 | +import org.slf4j.Logger; | |
| 18 | +import org.slf4j.LoggerFactory; | |
| 19 | +import org.springframework.beans.factory.InitializingBean; | |
| 20 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 21 | +import org.springframework.stereotype.Component; | |
| 22 | + | |
| 23 | +import javax.sip.InvalidArgumentException; | |
| 24 | +import javax.sip.RequestEvent; | |
| 25 | +import javax.sip.SipException; | |
| 26 | +import javax.sip.header.CallIdHeader; | |
| 27 | +import javax.sip.header.ContentTypeHeader; | |
| 28 | +import javax.sip.message.Response; | |
| 29 | +import java.text.ParseException; | |
| 30 | + | |
| 31 | +@Component | |
| 32 | +public class InfoRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { | |
| 33 | + | |
| 34 | + private final static Logger logger = LoggerFactory.getLogger(InfoRequestProcessor.class); | |
| 35 | + | |
| 36 | + private final String method = "INFO"; | |
| 37 | + | |
| 38 | + @Autowired | |
| 39 | + private SIPProcessorObserver sipProcessorObserver; | |
| 40 | + | |
| 41 | + @Autowired | |
| 42 | + private IVideoManagerStorage storage; | |
| 43 | + | |
| 44 | + @Autowired | |
| 45 | + private SipSubscribe sipSubscribe; | |
| 46 | + | |
| 47 | + @Autowired | |
| 48 | + private IRedisCatchStorage redisCatchStorage; | |
| 49 | + | |
| 50 | + @Autowired | |
| 51 | + private IInviteStreamService inviteStreamService; | |
| 52 | + | |
| 53 | + @Autowired | |
| 54 | + private IVideoManagerStorage storager; | |
| 55 | + | |
| 56 | + @Autowired | |
| 57 | + private SIPCommander cmder; | |
| 58 | + | |
| 59 | + @Autowired | |
| 60 | + private VideoStreamSessionManager sessionManager; | |
| 61 | + | |
| 62 | + @Override | |
| 63 | + public void afterPropertiesSet() throws Exception { | |
| 64 | + // 添加消息处理的订阅 | |
| 65 | + sipProcessorObserver.addRequestProcessor(method, this); | |
| 66 | + } | |
| 67 | + | |
| 68 | + @Override | |
| 69 | + public void process(RequestEvent evt) { | |
| 70 | + logger.debug("接收到消息:" + evt.getRequest()); | |
| 71 | + SIPRequest request = (SIPRequest) evt.getRequest(); | |
| 72 | + String deviceId = SipUtils.getUserIdFromFromHeader(request); | |
| 73 | + CallIdHeader callIdHeader = request.getCallIdHeader(); | |
| 74 | + // 先从会话内查找 | |
| 75 | + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); | |
| 76 | + | |
| 77 | + // 兼容海康 媒体通知 消息from字段不是设备ID的问题 | |
| 78 | + if (ssrcTransaction != null) { | |
| 79 | + deviceId = ssrcTransaction.getDeviceId(); | |
| 80 | + } | |
| 81 | + // 查询设备是否存在 | |
| 82 | + Device device = redisCatchStorage.getDevice(deviceId); | |
| 83 | + // 查询上级平台是否存在 | |
| 84 | + ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId); | |
| 85 | + try { | |
| 86 | + if (device != null && parentPlatform != null) { | |
| 87 | + logger.warn("[重复]平台与设备编号重复:{}", deviceId); | |
| 88 | + String hostAddress = request.getRemoteAddress().getHostAddress(); | |
| 89 | + int remotePort = request.getRemotePort(); | |
| 90 | + if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) { | |
| 91 | + parentPlatform = null; | |
| 92 | + }else { | |
| 93 | + device = null; | |
| 94 | + } | |
| 95 | + } | |
| 96 | + if (device == null && parentPlatform == null) { | |
| 97 | + // 不存在则回复404 | |
| 98 | + responseAck(request, Response.NOT_FOUND, "device "+ deviceId +" not found"); | |
| 99 | + logger.warn("[设备未找到 ]: {}", deviceId); | |
| 100 | + if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){ | |
| 101 | + DeviceNotFoundEvent deviceNotFoundEvent = new DeviceNotFoundEvent(evt.getDialog()); | |
| 102 | + deviceNotFoundEvent.setCallId(callIdHeader.getCallId()); | |
| 103 | + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent); | |
| 104 | + sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult); | |
| 105 | + }; | |
| 106 | + }else { | |
| 107 | + ContentTypeHeader header = (ContentTypeHeader)evt.getRequest().getHeader(ContentTypeHeader.NAME); | |
| 108 | + String contentType = header.getContentType(); | |
| 109 | + String contentSubType = header.getContentSubType(); | |
| 110 | + if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) { | |
| 111 | + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId()); | |
| 112 | + String streamId = sendRtpItem.getStreamId(); | |
| 113 | + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId); | |
| 114 | + if (null == inviteInfo) { | |
| 115 | + responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found"); | |
| 116 | + return; | |
| 117 | + } | |
| 118 | + Device device1 = storager.queryVideoDevice(inviteInfo.getDeviceId()); | |
| 119 | + if (inviteInfo.getStreamInfo() != null) { | |
| 120 | + cmder.playbackControlCmd(device1,inviteInfo.getStreamInfo(),new String(evt.getRequest().getRawContent()),eventResult -> { | |
| 121 | + // 失败的回复 | |
| 122 | + try { | |
| 123 | + responseAck(request, eventResult.statusCode, eventResult.msg); | |
| 124 | + } catch (SipException | InvalidArgumentException | ParseException e) { | |
| 125 | + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage()); | |
| 126 | + } | |
| 127 | + }, eventResult -> { | |
| 128 | + // 成功的回复 | |
| 129 | + try { | |
| 130 | + responseAck(request, eventResult.statusCode); | |
| 131 | + } catch (SipException | InvalidArgumentException | ParseException e) { | |
| 132 | + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage()); | |
| 133 | + } | |
| 134 | + }); | |
| 135 | + } | |
| 136 | + | |
| 137 | + } | |
| 138 | + } | |
| 139 | + } catch (SipException e) { | |
| 140 | + logger.warn("SIP 回复错误", e); | |
| 141 | + } catch (InvalidArgumentException e) { | |
| 142 | + logger.warn("参数无效", e); | |
| 143 | + } catch (ParseException e) { | |
| 144 | + logger.warn("SIP回复时解析异常", e); | |
| 145 | + } | |
| 146 | + } | |
| 147 | + | |
| 148 | + | |
| 149 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/IMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/ControlMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/NotifyMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
100644 → 100755
| ... | ... | @@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.utils.SipUtils; |
| 13 | 13 | import com.genersoft.iot.vmp.service.IDeviceService; |
| 14 | 14 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 15 | 15 | import gov.nist.javax.sip.message.SIPRequest; |
| 16 | +import org.apache.commons.lang3.ObjectUtils; | |
| 16 | 17 | import org.dom4j.Element; |
| 17 | 18 | import org.slf4j.Logger; |
| 18 | 19 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -68,7 +69,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp |
| 68 | 69 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 69 | 70 | logger.error("[命令发送失败] 心跳回复: {}", e.getMessage()); |
| 70 | 71 | } |
| 71 | - if (DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L){ | |
| 72 | + if (!ObjectUtils.isEmpty(device.getKeepaliveTime()) && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L) { | |
| 72 | 73 | logger.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId()); |
| 73 | 74 | return; |
| 74 | 75 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/QueryMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/AlarmQueryMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/ISIPResponseProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/SIPResponseProcessorAbstract.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/ByeResponseProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/CancelResponseProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/ITimeoutProcessor.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
| 1 | -package com.genersoft.iot.vmp.gb28181.utils; | |
| 2 | - | |
| 3 | -import com.alibaba.fastjson2.JSONArray; | |
| 4 | -import com.alibaba.fastjson2.JSONObject; | |
| 5 | -import com.genersoft.iot.vmp.common.CivilCodePo; | |
| 6 | -import com.genersoft.iot.vmp.conf.CivilCodeFileConf; | |
| 7 | -import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 8 | -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 9 | -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | |
| 10 | -import com.genersoft.iot.vmp.utils.DateUtil; | |
| 11 | -import org.apache.commons.lang3.math.NumberUtils; | |
| 12 | -import org.dom4j.Attribute; | |
| 13 | -import org.dom4j.Document; | |
| 14 | -import org.dom4j.DocumentException; | |
| 15 | -import org.dom4j.Element; | |
| 16 | -import org.dom4j.io.SAXReader; | |
| 17 | -import org.slf4j.Logger; | |
| 18 | -import org.slf4j.LoggerFactory; | |
| 19 | -import org.springframework.util.ObjectUtils; | |
| 20 | -import org.springframework.util.ReflectionUtils; | |
| 21 | - | |
| 22 | -import javax.sip.RequestEvent; | |
| 23 | -import javax.sip.message.Request; | |
| 24 | -import java.io.ByteArrayInputStream; | |
| 25 | -import java.io.StringReader; | |
| 26 | -import java.lang.reflect.Field; | |
| 27 | -import java.lang.reflect.InvocationTargetException; | |
| 28 | -import java.lang.reflect.ParameterizedType; | |
| 29 | -import java.lang.reflect.Type; | |
| 30 | -import java.util.*; | |
| 31 | - | |
| 32 | -/** | |
| 33 | - * 基于dom4j的工具包 | |
| 34 | - * | |
| 35 | - * | |
| 36 | - */ | |
| 37 | -public class XmlUtil { | |
| 38 | - /** | |
| 39 | - * 日志服务 | |
| 40 | - */ | |
| 41 | - private static Logger logger = LoggerFactory.getLogger(XmlUtil.class); | |
| 42 | - | |
| 43 | - /** | |
| 44 | - * 解析XML为Document对象 | |
| 45 | - * | |
| 46 | - * @param xml 被解析的XMl | |
| 47 | - * | |
| 48 | - * @return Document | |
| 49 | - */ | |
| 50 | - public static Element parseXml(String xml) { | |
| 51 | - Document document = null; | |
| 52 | - // | |
| 53 | - StringReader sr = new StringReader(xml); | |
| 54 | - SAXReader saxReader = new SAXReader(); | |
| 55 | - try { | |
| 56 | - document = saxReader.read(sr); | |
| 57 | - } catch (DocumentException e) { | |
| 58 | - logger.error("解析失败", e); | |
| 59 | - } | |
| 60 | - return null == document ? null : document.getRootElement(); | |
| 61 | - } | |
| 62 | - | |
| 63 | - /** | |
| 64 | - * 获取element对象的text的值 | |
| 65 | - * | |
| 66 | - * @param em 节点的对象 | |
| 67 | - * @param tag 节点的tag | |
| 68 | - * @return 节点 | |
| 69 | - */ | |
| 70 | - public static String getText(Element em, String tag) { | |
| 71 | - if (null == em) { | |
| 72 | - return null; | |
| 73 | - } | |
| 74 | - Element e = em.element(tag); | |
| 75 | - // | |
| 76 | - return null == e ? null : e.getText().trim(); | |
| 77 | - } | |
| 78 | - | |
| 79 | - /** | |
| 80 | - * 递归解析xml节点,适用于 多节点数据 | |
| 81 | - * | |
| 82 | - * @param node node | |
| 83 | - * @param nodeName nodeName | |
| 84 | - * @return List<Map<String, Object>> | |
| 85 | - */ | |
| 86 | - public static List<Map<String, Object>> listNodes(Element node, String nodeName) { | |
| 87 | - if (null == node) { | |
| 88 | - return null; | |
| 89 | - } | |
| 90 | - // 初始化返回 | |
| 91 | - List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>(); | |
| 92 | - // 首先获取当前节点的所有属性节点 | |
| 93 | - List<Attribute> list = node.attributes(); | |
| 94 | - | |
| 95 | - Map<String, Object> map = null; | |
| 96 | - // 遍历属性节点 | |
| 97 | - for (Attribute attribute : list) { | |
| 98 | - if (nodeName.equals(node.getName())) { | |
| 99 | - if (null == map) { | |
| 100 | - map = new HashMap<String, Object>(); | |
| 101 | - listMap.add(map); | |
| 102 | - } | |
| 103 | - // 取到的节点属性放到map中 | |
| 104 | - map.put(attribute.getName(), attribute.getValue()); | |
| 105 | - } | |
| 106 | - | |
| 107 | - } | |
| 108 | - // 遍历当前节点下的所有节点 ,nodeName 要解析的节点名称 | |
| 109 | - // 使用递归 | |
| 110 | - Iterator<Element> iterator = node.elementIterator(); | |
| 111 | - while (iterator.hasNext()) { | |
| 112 | - Element e = iterator.next(); | |
| 113 | - listMap.addAll(listNodes(e, nodeName)); | |
| 114 | - } | |
| 115 | - return listMap; | |
| 116 | - } | |
| 117 | - | |
| 118 | - /** | |
| 119 | - * xml转json | |
| 120 | - * | |
| 121 | - * @param element | |
| 122 | - * @param json | |
| 123 | - */ | |
| 124 | - public static void node2Json(Element element, JSONObject json) { | |
| 125 | - // 如果是属性 | |
| 126 | - for (Object o : element.attributes()) { | |
| 127 | - Attribute attr = (Attribute) o; | |
| 128 | - if (!ObjectUtils.isEmpty(attr.getValue())) { | |
| 129 | - json.put("@" + attr.getName(), attr.getValue()); | |
| 130 | - } | |
| 131 | - } | |
| 132 | - List<Element> chdEl = element.elements(); | |
| 133 | - if (chdEl.isEmpty() && !ObjectUtils.isEmpty(element.getText())) {// 如果没有子元素,只有一个值 | |
| 134 | - json.put(element.getName(), element.getText()); | |
| 135 | - } | |
| 136 | - | |
| 137 | - for (Element e : chdEl) { // 有子元素 | |
| 138 | - if (!e.elements().isEmpty()) { // 子元素也有子元素 | |
| 139 | - JSONObject chdjson = new JSONObject(); | |
| 140 | - node2Json(e, chdjson); | |
| 141 | - Object o = json.get(e.getName()); | |
| 142 | - if (o != null) { | |
| 143 | - JSONArray jsona = null; | |
| 144 | - if (o instanceof JSONObject) { // 如果此元素已存在,则转为jsonArray | |
| 145 | - JSONObject jsono = (JSONObject) o; | |
| 146 | - json.remove(e.getName()); | |
| 147 | - jsona = new JSONArray(); | |
| 148 | - jsona.add(jsono); | |
| 149 | - jsona.add(chdjson); | |
| 150 | - } | |
| 151 | - if (o instanceof JSONArray) { | |
| 152 | - jsona = (JSONArray) o; | |
| 153 | - jsona.add(chdjson); | |
| 154 | - } | |
| 155 | - json.put(e.getName(), jsona); | |
| 156 | - } else { | |
| 157 | - if (!chdjson.isEmpty()) { | |
| 158 | - json.put(e.getName(), chdjson); | |
| 159 | - } | |
| 160 | - } | |
| 161 | - } else { // 子元素没有子元素 | |
| 162 | - for (Object o : element.attributes()) { | |
| 163 | - Attribute attr = (Attribute) o; | |
| 164 | - if (!ObjectUtils.isEmpty(attr.getValue())) { | |
| 165 | - json.put("@" + attr.getName(), attr.getValue()); | |
| 166 | - } | |
| 167 | - } | |
| 168 | - if (!e.getText().isEmpty()) { | |
| 169 | - json.put(e.getName(), e.getText()); | |
| 170 | - } | |
| 171 | - } | |
| 172 | - } | |
| 173 | - } | |
| 174 | - public static Element getRootElement(RequestEvent evt) throws DocumentException { | |
| 175 | - | |
| 176 | - return getRootElement(evt, "gb2312"); | |
| 177 | - } | |
| 178 | - | |
| 179 | - public static Element getRootElement(RequestEvent evt, String charset) throws DocumentException { | |
| 180 | - Request request = evt.getRequest(); | |
| 181 | - return getRootElement(request.getRawContent(), charset); | |
| 182 | - } | |
| 183 | - | |
| 184 | - public static Element getRootElement(byte[] content, String charset) throws DocumentException { | |
| 185 | - if (charset == null) { | |
| 186 | - charset = "gb2312"; | |
| 187 | - } | |
| 188 | - SAXReader reader = new SAXReader(); | |
| 189 | - reader.setEncoding(charset); | |
| 190 | - Document xml = reader.read(new ByteArrayInputStream(content)); | |
| 191 | - return xml.getRootElement(); | |
| 192 | - } | |
| 193 | - | |
| 194 | - private enum ChannelType{ | |
| 195 | - CivilCode, BusinessGroup,VirtualOrganization,Other | |
| 196 | - } | |
| 197 | - | |
| 198 | - public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event, CivilCodeFileConf civilCodeFileConf){ | |
| 199 | - DeviceChannel deviceChannel = new DeviceChannel(); | |
| 200 | - deviceChannel.setDeviceId(device.getDeviceId()); | |
| 201 | - Element channdelIdElement = itemDevice.element("DeviceID"); | |
| 202 | - if (channdelIdElement == null) { | |
| 203 | - logger.warn("解析Catalog消息时发现缺少 DeviceID"); | |
| 204 | - return null; | |
| 205 | - } | |
| 206 | - String channelId = channdelIdElement.getTextTrim(); | |
| 207 | - if (ObjectUtils.isEmpty(channelId)) { | |
| 208 | - logger.warn("解析Catalog消息时发现缺少 DeviceID"); | |
| 209 | - return null; | |
| 210 | - } | |
| 211 | - deviceChannel.setChannelId(channelId); | |
| 212 | - if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) { | |
| 213 | - // 除了ADD和update情况下需要识别全部内容, | |
| 214 | - return deviceChannel; | |
| 215 | - } | |
| 216 | - Element nameElement = itemDevice.element("Name"); | |
| 217 | - if (nameElement != null) { | |
| 218 | - deviceChannel.setName(nameElement.getText()); | |
| 219 | - } | |
| 220 | - if(channelId.length() <= 8) { | |
| 221 | - deviceChannel.setHasAudio(false); | |
| 222 | - CivilCodePo parentCode = civilCodeFileConf.getParentCode(channelId); | |
| 223 | - if (parentCode != null) { | |
| 224 | - deviceChannel.setParentId(parentCode.getCode()); | |
| 225 | - deviceChannel.setCivilCode(parentCode.getCode()); | |
| 226 | - }else { | |
| 227 | - logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId); | |
| 228 | - } | |
| 229 | - deviceChannel.setStatus(true); | |
| 230 | - return deviceChannel; | |
| 231 | - }else { | |
| 232 | - if(channelId.length() != 20) { | |
| 233 | - logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId); | |
| 234 | - return null; | |
| 235 | - } | |
| 236 | - | |
| 237 | - int code = Integer.parseInt(channelId.substring(10, 13)); | |
| 238 | - if (code == 136 || code == 137 || code == 138) { | |
| 239 | - deviceChannel.setHasAudio(true); | |
| 240 | - }else { | |
| 241 | - deviceChannel.setHasAudio(false); | |
| 242 | - } | |
| 243 | - // 设备厂商 | |
| 244 | - String manufacturer = getText(itemDevice, "Manufacturer"); | |
| 245 | - // 设备型号 | |
| 246 | - String model = getText(itemDevice, "Model"); | |
| 247 | - // 设备归属 | |
| 248 | - String owner = getText(itemDevice, "Owner"); | |
| 249 | - // 行政区域 | |
| 250 | - String civilCode = getText(itemDevice, "CivilCode"); | |
| 251 | - // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织 | |
| 252 | - String businessGroupID = getText(itemDevice, "BusinessGroupID"); | |
| 253 | - // 父设备/区域/系统ID | |
| 254 | - String parentID = getText(itemDevice, "ParentID"); | |
| 255 | - if (parentID != null && parentID.equalsIgnoreCase("null")) { | |
| 256 | - parentID = null; | |
| 257 | - } | |
| 258 | - // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式 | |
| 259 | - String registerWay = getText(itemDevice, "RegisterWay"); | |
| 260 | - // 保密属性(必选)缺省为0;0:不涉密,1:涉密 | |
| 261 | - String secrecy = getText(itemDevice, "Secrecy"); | |
| 262 | - // 安装地址 | |
| 263 | - String address = getText(itemDevice, "Address"); | |
| 264 | - | |
| 265 | - switch (code){ | |
| 266 | - case 200: | |
| 267 | - // 系统目录 | |
| 268 | - if (!ObjectUtils.isEmpty(manufacturer)) { | |
| 269 | - deviceChannel.setManufacture(manufacturer); | |
| 270 | - } | |
| 271 | - if (!ObjectUtils.isEmpty(model)) { | |
| 272 | - deviceChannel.setModel(model); | |
| 273 | - } | |
| 274 | - if (!ObjectUtils.isEmpty(owner)) { | |
| 275 | - deviceChannel.setOwner(owner); | |
| 276 | - } | |
| 277 | - if (!ObjectUtils.isEmpty(civilCode)) { | |
| 278 | - deviceChannel.setCivilCode(civilCode); | |
| 279 | - deviceChannel.setParentId(civilCode); | |
| 280 | - }else { | |
| 281 | - if (!ObjectUtils.isEmpty(parentID)) { | |
| 282 | - deviceChannel.setParentId(parentID); | |
| 283 | - } | |
| 284 | - } | |
| 285 | - if (!ObjectUtils.isEmpty(address)) { | |
| 286 | - deviceChannel.setAddress(address); | |
| 287 | - } | |
| 288 | - deviceChannel.setStatus(true); | |
| 289 | - if (!ObjectUtils.isEmpty(registerWay)) { | |
| 290 | - try { | |
| 291 | - deviceChannel.setRegisterWay(Integer.parseInt(registerWay)); | |
| 292 | - }catch (NumberFormatException exception) { | |
| 293 | - logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); | |
| 294 | - } | |
| 295 | - } | |
| 296 | - if (!ObjectUtils.isEmpty(secrecy)) { | |
| 297 | - deviceChannel.setSecrecy(secrecy); | |
| 298 | - } | |
| 299 | - return deviceChannel; | |
| 300 | - case 215: | |
| 301 | - // 业务分组 | |
| 302 | - deviceChannel.setStatus(true); | |
| 303 | - if (!ObjectUtils.isEmpty(parentID)) { | |
| 304 | - if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) { | |
| 305 | - deviceChannel.setParentId(parentID); | |
| 306 | - } | |
| 307 | - }else { | |
| 308 | - logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId"); | |
| 309 | - if (!ObjectUtils.isEmpty(civilCode)) { | |
| 310 | - deviceChannel.setCivilCode(civilCode); | |
| 311 | - } | |
| 312 | - } | |
| 313 | - break; | |
| 314 | - case 216: | |
| 315 | - // 虚拟组织 | |
| 316 | - deviceChannel.setStatus(true); | |
| 317 | - if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 318 | - deviceChannel.setBusinessGroupId(businessGroupID); | |
| 319 | - } | |
| 320 | - | |
| 321 | - if (!ObjectUtils.isEmpty(parentID)) { | |
| 322 | - if (parentID.contains("/")) { | |
| 323 | - String[] parentIdArray = parentID.split("/"); | |
| 324 | - parentID = parentIdArray[parentIdArray.length - 1]; | |
| 325 | - } | |
| 326 | - deviceChannel.setParentId(parentID); | |
| 327 | - }else { | |
| 328 | - if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 329 | - deviceChannel.setParentId(businessGroupID); | |
| 330 | - } | |
| 331 | - } | |
| 332 | - break; | |
| 333 | - default: | |
| 334 | - // 设备目录 | |
| 335 | - if (!ObjectUtils.isEmpty(manufacturer)) { | |
| 336 | - deviceChannel.setManufacture(manufacturer); | |
| 337 | - } | |
| 338 | - if (!ObjectUtils.isEmpty(model)) { | |
| 339 | - deviceChannel.setModel(model); | |
| 340 | - } | |
| 341 | - if (!ObjectUtils.isEmpty(owner)) { | |
| 342 | - deviceChannel.setOwner(owner); | |
| 343 | - } | |
| 344 | - if (!ObjectUtils.isEmpty(civilCode) | |
| 345 | - && civilCode.length() <= 8 | |
| 346 | - && NumberUtils.isParsable(civilCode) | |
| 347 | - && civilCode.length()%2 == 0 | |
| 348 | - ) { | |
| 349 | - deviceChannel.setCivilCode(civilCode); | |
| 350 | - } | |
| 351 | - if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 352 | - deviceChannel.setBusinessGroupId(businessGroupID); | |
| 353 | - } | |
| 354 | - | |
| 355 | - // 警区 | |
| 356 | - String block = getText(itemDevice, "Block"); | |
| 357 | - if (!ObjectUtils.isEmpty(block)) { | |
| 358 | - deviceChannel.setBlock(block); | |
| 359 | - } | |
| 360 | - if (!ObjectUtils.isEmpty(address)) { | |
| 361 | - deviceChannel.setAddress(address); | |
| 362 | - } | |
| 363 | - | |
| 364 | - if (!ObjectUtils.isEmpty(secrecy)) { | |
| 365 | - deviceChannel.setSecrecy(secrecy); | |
| 366 | - } | |
| 367 | - | |
| 368 | - // 当为设备时,是否有子设备(必选)1有,0没有 | |
| 369 | - String parental = getText(itemDevice, "Parental"); | |
| 370 | - if (!ObjectUtils.isEmpty(parental)) { | |
| 371 | - try { | |
| 372 | - // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 | |
| 373 | - if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) { | |
| 374 | - deviceChannel.setParental(0); | |
| 375 | - }else { | |
| 376 | - deviceChannel.setParental(1); | |
| 377 | - } | |
| 378 | - }catch (NumberFormatException e) { | |
| 379 | - logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental); | |
| 380 | - } | |
| 381 | - } | |
| 382 | - // 父设备/区域/系统ID | |
| 383 | - | |
| 384 | - if (!ObjectUtils.isEmpty(parentID) ) { | |
| 385 | - if (parentID.contains("/")) { | |
| 386 | - String[] parentIdArray = parentID.split("/"); | |
| 387 | - deviceChannel.setParentId(parentIdArray[parentIdArray.length - 1]); | |
| 388 | - }else { | |
| 389 | - if (parentID.length()%2 == 0) { | |
| 390 | - deviceChannel.setParentId(parentID); | |
| 391 | - }else { | |
| 392 | - logger.warn("[xml解析] 不规范的parentID:{}, 已舍弃", parentID); | |
| 393 | - } | |
| 394 | - } | |
| 395 | - }else { | |
| 396 | - if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 397 | - deviceChannel.setParentId(businessGroupID); | |
| 398 | - }else { | |
| 399 | - if (!ObjectUtils.isEmpty(deviceChannel.getCivilCode())) { | |
| 400 | - deviceChannel.setParentId(deviceChannel.getCivilCode()); | |
| 401 | - } | |
| 402 | - } | |
| 403 | - } | |
| 404 | - // 注册方式 | |
| 405 | - if (!ObjectUtils.isEmpty(registerWay)) { | |
| 406 | - try { | |
| 407 | - int registerWayInt = Integer.parseInt(registerWay); | |
| 408 | - deviceChannel.setRegisterWay(registerWayInt); | |
| 409 | - }catch (NumberFormatException exception) { | |
| 410 | - logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); | |
| 411 | - deviceChannel.setRegisterWay(1); | |
| 412 | - } | |
| 413 | - }else { | |
| 414 | - deviceChannel.setRegisterWay(1); | |
| 415 | - } | |
| 416 | - | |
| 417 | - // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式 | |
| 418 | - String safetyWay = getText(itemDevice, "SafetyWay"); | |
| 419 | - if (!ObjectUtils.isEmpty(safetyWay)) { | |
| 420 | - try { | |
| 421 | - deviceChannel.setSafetyWay(Integer.parseInt(safetyWay)); | |
| 422 | - }catch (NumberFormatException e) { | |
| 423 | - logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay); | |
| 424 | - } | |
| 425 | - } | |
| 426 | - | |
| 427 | - // 证书序列号(有证书的设备必选) | |
| 428 | - String certNum = getText(itemDevice, "CertNum"); | |
| 429 | - if (!ObjectUtils.isEmpty(certNum)) { | |
| 430 | - deviceChannel.setCertNum(certNum); | |
| 431 | - } | |
| 432 | - | |
| 433 | - // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效 | |
| 434 | - String certifiable = getText(itemDevice, "Certifiable"); | |
| 435 | - if (!ObjectUtils.isEmpty(certifiable)) { | |
| 436 | - try { | |
| 437 | - deviceChannel.setCertifiable(Integer.parseInt(certifiable)); | |
| 438 | - }catch (NumberFormatException e) { | |
| 439 | - logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable); | |
| 440 | - } | |
| 441 | - } | |
| 442 | - | |
| 443 | - // 无效原因码(有证书且证书无效的设备必选) | |
| 444 | - String errCode = getText(itemDevice, "ErrCode"); | |
| 445 | - if (!ObjectUtils.isEmpty(errCode)) { | |
| 446 | - try { | |
| 447 | - deviceChannel.setErrCode(Integer.parseInt(errCode)); | |
| 448 | - }catch (NumberFormatException e) { | |
| 449 | - logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode); | |
| 450 | - } | |
| 451 | - } | |
| 452 | - | |
| 453 | - // 证书终止有效期(有证书的设备必选) | |
| 454 | - String endTime = getText(itemDevice, "EndTime"); | |
| 455 | - if (!ObjectUtils.isEmpty(endTime)) { | |
| 456 | - deviceChannel.setEndTime(endTime); | |
| 457 | - } | |
| 458 | - | |
| 459 | - | |
| 460 | - // 设备/区域/系统IP地址 | |
| 461 | - String ipAddress = getText(itemDevice, "IPAddress"); | |
| 462 | - if (!ObjectUtils.isEmpty(ipAddress)) { | |
| 463 | - deviceChannel.setIpAddress(ipAddress); | |
| 464 | - } | |
| 465 | - | |
| 466 | - // 设备/区域/系统端口 | |
| 467 | - String port = getText(itemDevice, "Port"); | |
| 468 | - if (!ObjectUtils.isEmpty(port)) { | |
| 469 | - try { | |
| 470 | - deviceChannel.setPort(Integer.parseInt(port)); | |
| 471 | - }catch (NumberFormatException e) { | |
| 472 | - logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port); | |
| 473 | - } | |
| 474 | - } | |
| 475 | - | |
| 476 | - // 设备口令 | |
| 477 | - String password = getText(itemDevice, "Password"); | |
| 478 | - if (!ObjectUtils.isEmpty(password)) { | |
| 479 | - deviceChannel.setPassword(password); | |
| 480 | - } | |
| 481 | - | |
| 482 | - | |
| 483 | - // 设备状态 | |
| 484 | - String status = getText(itemDevice, "Status"); | |
| 485 | - if (status != null) { | |
| 486 | - // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 | |
| 487 | - if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) { | |
| 488 | - deviceChannel.setStatus(true); | |
| 489 | - } | |
| 490 | - if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { | |
| 491 | - deviceChannel.setStatus(false); | |
| 492 | - } | |
| 493 | - }else { | |
| 494 | - deviceChannel.setStatus(true); | |
| 495 | - } | |
| 496 | - | |
| 497 | - // 经度 | |
| 498 | - String longitude = getText(itemDevice, "Longitude"); | |
| 499 | - if (NumericUtil.isDouble(longitude)) { | |
| 500 | - deviceChannel.setLongitude(Double.parseDouble(longitude)); | |
| 501 | - } else { | |
| 502 | - deviceChannel.setLongitude(0.00); | |
| 503 | - } | |
| 504 | - | |
| 505 | - // 纬度 | |
| 506 | - String latitude = getText(itemDevice, "Latitude"); | |
| 507 | - if (NumericUtil.isDouble(latitude)) { | |
| 508 | - deviceChannel.setLatitude(Double.parseDouble(latitude)); | |
| 509 | - } else { | |
| 510 | - deviceChannel.setLatitude(0.00); | |
| 511 | - } | |
| 512 | - | |
| 513 | - deviceChannel.setGpsTime(DateUtil.getNow()); | |
| 514 | - | |
| 515 | - // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选 | |
| 516 | - String ptzType = getText(itemDevice, "PTZType"); | |
| 517 | - if (ObjectUtils.isEmpty(ptzType)) { | |
| 518 | - //兼容INFO中的信息 | |
| 519 | - Element info = itemDevice.element("Info"); | |
| 520 | - String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType"); | |
| 521 | - if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){ | |
| 522 | - try { | |
| 523 | - deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo)); | |
| 524 | - }catch (NumberFormatException e){ | |
| 525 | - logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo); | |
| 526 | - } | |
| 527 | - } | |
| 528 | - } else { | |
| 529 | - try { | |
| 530 | - deviceChannel.setPTZType(Integer.parseInt(ptzType)); | |
| 531 | - }catch (NumberFormatException e){ | |
| 532 | - logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType); | |
| 533 | - } | |
| 534 | - } | |
| 535 | - | |
| 536 | - // TODO 摄像机位置类型扩展。 | |
| 537 | - // 1-省际检查站、 | |
| 538 | - // 2-党政机关、 | |
| 539 | - // 3-车站码头、 | |
| 540 | - // 4-中心广场、 | |
| 541 | - // 5-体育场馆、 | |
| 542 | - // 6-商业中心、 | |
| 543 | - // 7-宗教场所、 | |
| 544 | - // 8-校园周边、 | |
| 545 | - // 9-治安复杂区域、 | |
| 546 | - // 10-交通干线。 | |
| 547 | - // String positionType = getText(itemDevice, "PositionType"); | |
| 548 | - | |
| 549 | - // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。 | |
| 550 | - // String roomType = getText(itemDevice, "RoomType"); | |
| 551 | - // TODO 摄像机用途属性 | |
| 552 | - // String useType = getText(itemDevice, "UseType"); | |
| 553 | - // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光 | |
| 554 | - // String supplyLightType = getText(itemDevice, "SupplyLightType"); | |
| 555 | - // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。 | |
| 556 | - // String directionType = getText(itemDevice, "DirectionType"); | |
| 557 | - // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定 | |
| 558 | - // String resolution = getText(itemDevice, "Resolution"); | |
| 559 | - | |
| 560 | - // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4 | |
| 561 | - // String downloadSpeed = getText(itemDevice, "DownloadSpeed"); | |
| 562 | - // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层) | |
| 563 | - // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode"); | |
| 564 | - // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强 | |
| 565 | - // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode"); | |
| 566 | - | |
| 567 | - | |
| 568 | - deviceChannel.setSecrecy(secrecy); | |
| 569 | - break; | |
| 570 | - } | |
| 571 | - } | |
| 572 | - | |
| 573 | - return deviceChannel; | |
| 574 | - } | |
| 575 | - | |
| 576 | - /** | |
| 577 | - * 新增方法支持内部嵌套 | |
| 578 | - * | |
| 579 | - * @param element xmlElement | |
| 580 | - * @param clazz 结果类 | |
| 581 | - * @param <T> 泛型 | |
| 582 | - * @return 结果对象 | |
| 583 | - * @throws NoSuchMethodException | |
| 584 | - * @throws InvocationTargetException | |
| 585 | - * @throws InstantiationException | |
| 586 | - * @throws IllegalAccessException | |
| 587 | - */ | |
| 588 | - public static <T> T loadElement(Element element, Class<T> clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { | |
| 589 | - Field[] fields = clazz.getDeclaredFields(); | |
| 590 | - T t = clazz.getDeclaredConstructor().newInstance(); | |
| 591 | - for (Field field : fields) { | |
| 592 | - ReflectionUtils.makeAccessible(field); | |
| 593 | - MessageElement annotation = field.getAnnotation(MessageElement.class); | |
| 594 | - if (annotation == null) { | |
| 595 | - continue; | |
| 596 | - } | |
| 597 | - String value = annotation.value(); | |
| 598 | - String subVal = annotation.subVal(); | |
| 599 | - Element element1 = element.element(value); | |
| 600 | - if (element1 == null) { | |
| 601 | - continue; | |
| 602 | - } | |
| 603 | - if ("".equals(subVal)) { | |
| 604 | - // 无下级数据 | |
| 605 | - Object fieldVal = element1.isTextOnly() ? element1.getText() : loadElement(element1, field.getType()); | |
| 606 | - Object o = simpleTypeDeal(field.getType(), fieldVal); | |
| 607 | - ReflectionUtils.setField(field, t, o); | |
| 608 | - } else { | |
| 609 | - // 存在下级数据 | |
| 610 | - ArrayList<Object> list = new ArrayList<>(); | |
| 611 | - Type genericType = field.getGenericType(); | |
| 612 | - if (!(genericType instanceof ParameterizedType)) { | |
| 613 | - continue; | |
| 614 | - } | |
| 615 | - Class<?> aClass = (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0]; | |
| 616 | - for (Element element2 : element1.elements(subVal)) { | |
| 617 | - list.add(loadElement(element2, aClass)); | |
| 618 | - } | |
| 619 | - ReflectionUtils.setField(field, t, list); | |
| 620 | - } | |
| 621 | - } | |
| 622 | - return t; | |
| 623 | - } | |
| 624 | - | |
| 625 | - /** | |
| 626 | - * 简单类型处理 | |
| 627 | - * | |
| 628 | - * @param tClass | |
| 629 | - * @param val | |
| 630 | - * @return | |
| 631 | - */ | |
| 632 | - private static Object simpleTypeDeal(Class<?> tClass, Object val) { | |
| 633 | - if (tClass.equals(String.class)) { | |
| 634 | - return val.toString(); | |
| 635 | - } | |
| 636 | - if (tClass.equals(Integer.class)) { | |
| 637 | - return Integer.valueOf(val.toString()); | |
| 638 | - } | |
| 639 | - if (tClass.equals(Double.class)) { | |
| 640 | - return Double.valueOf(val.toString()); | |
| 641 | - } | |
| 642 | - if (tClass.equals(Long.class)) { | |
| 643 | - return Long.valueOf(val.toString()); | |
| 644 | - } | |
| 645 | - return val; | |
| 646 | - } | |
| 1 | +package com.genersoft.iot.vmp.gb28181.utils; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson2.JSONArray; | |
| 4 | +import com.alibaba.fastjson2.JSONObject; | |
| 5 | +import com.genersoft.iot.vmp.common.CivilCodePo; | |
| 6 | +import com.genersoft.iot.vmp.conf.CivilCodeFileConf; | |
| 7 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 9 | +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | |
| 10 | +import com.genersoft.iot.vmp.utils.DateUtil; | |
| 11 | +import org.apache.commons.lang3.math.NumberUtils; | |
| 12 | +import org.dom4j.Attribute; | |
| 13 | +import org.dom4j.Document; | |
| 14 | +import org.dom4j.DocumentException; | |
| 15 | +import org.dom4j.Element; | |
| 16 | +import org.dom4j.io.SAXReader; | |
| 17 | +import org.slf4j.Logger; | |
| 18 | +import org.slf4j.LoggerFactory; | |
| 19 | +import org.springframework.util.ObjectUtils; | |
| 20 | +import org.springframework.util.ReflectionUtils; | |
| 21 | + | |
| 22 | +import javax.sip.RequestEvent; | |
| 23 | +import javax.sip.message.Request; | |
| 24 | +import java.io.ByteArrayInputStream; | |
| 25 | +import java.io.StringReader; | |
| 26 | +import java.lang.reflect.Field; | |
| 27 | +import java.lang.reflect.InvocationTargetException; | |
| 28 | +import java.lang.reflect.ParameterizedType; | |
| 29 | +import java.lang.reflect.Type; | |
| 30 | +import java.util.*; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * 基于dom4j的工具包 | |
| 34 | + * | |
| 35 | + * | |
| 36 | + */ | |
| 37 | +public class XmlUtil { | |
| 38 | + /** | |
| 39 | + * 日志服务 | |
| 40 | + */ | |
| 41 | + private static Logger logger = LoggerFactory.getLogger(XmlUtil.class); | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * 解析XML为Document对象 | |
| 45 | + * | |
| 46 | + * @param xml 被解析的XMl | |
| 47 | + * | |
| 48 | + * @return Document | |
| 49 | + */ | |
| 50 | + public static Element parseXml(String xml) { | |
| 51 | + Document document = null; | |
| 52 | + // | |
| 53 | + StringReader sr = new StringReader(xml); | |
| 54 | + SAXReader saxReader = new SAXReader(); | |
| 55 | + try { | |
| 56 | + document = saxReader.read(sr); | |
| 57 | + } catch (DocumentException e) { | |
| 58 | + logger.error("解析失败", e); | |
| 59 | + } | |
| 60 | + return null == document ? null : document.getRootElement(); | |
| 61 | + } | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * 获取element对象的text的值 | |
| 65 | + * | |
| 66 | + * @param em 节点的对象 | |
| 67 | + * @param tag 节点的tag | |
| 68 | + * @return 节点 | |
| 69 | + */ | |
| 70 | + public static String getText(Element em, String tag) { | |
| 71 | + if (null == em) { | |
| 72 | + return null; | |
| 73 | + } | |
| 74 | + Element e = em.element(tag); | |
| 75 | + // | |
| 76 | + return null == e ? null : e.getText().trim(); | |
| 77 | + } | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * 递归解析xml节点,适用于 多节点数据 | |
| 81 | + * | |
| 82 | + * @param node node | |
| 83 | + * @param nodeName nodeName | |
| 84 | + * @return List<Map<String, Object>> | |
| 85 | + */ | |
| 86 | + public static List<Map<String, Object>> listNodes(Element node, String nodeName) { | |
| 87 | + if (null == node) { | |
| 88 | + return null; | |
| 89 | + } | |
| 90 | + // 初始化返回 | |
| 91 | + List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>(); | |
| 92 | + // 首先获取当前节点的所有属性节点 | |
| 93 | + List<Attribute> list = node.attributes(); | |
| 94 | + | |
| 95 | + Map<String, Object> map = null; | |
| 96 | + // 遍历属性节点 | |
| 97 | + for (Attribute attribute : list) { | |
| 98 | + if (nodeName.equals(node.getName())) { | |
| 99 | + if (null == map) { | |
| 100 | + map = new HashMap<String, Object>(); | |
| 101 | + listMap.add(map); | |
| 102 | + } | |
| 103 | + // 取到的节点属性放到map中 | |
| 104 | + map.put(attribute.getName(), attribute.getValue()); | |
| 105 | + } | |
| 106 | + | |
| 107 | + } | |
| 108 | + // 遍历当前节点下的所有节点 ,nodeName 要解析的节点名称 | |
| 109 | + // 使用递归 | |
| 110 | + Iterator<Element> iterator = node.elementIterator(); | |
| 111 | + while (iterator.hasNext()) { | |
| 112 | + Element e = iterator.next(); | |
| 113 | + listMap.addAll(listNodes(e, nodeName)); | |
| 114 | + } | |
| 115 | + return listMap; | |
| 116 | + } | |
| 117 | + | |
| 118 | + /** | |
| 119 | + * xml转json | |
| 120 | + * | |
| 121 | + * @param element | |
| 122 | + * @param json | |
| 123 | + */ | |
| 124 | + public static void node2Json(Element element, JSONObject json) { | |
| 125 | + // 如果是属性 | |
| 126 | + for (Object o : element.attributes()) { | |
| 127 | + Attribute attr = (Attribute) o; | |
| 128 | + if (!ObjectUtils.isEmpty(attr.getValue())) { | |
| 129 | + json.put("@" + attr.getName(), attr.getValue()); | |
| 130 | + } | |
| 131 | + } | |
| 132 | + List<Element> chdEl = element.elements(); | |
| 133 | + if (chdEl.isEmpty() && !ObjectUtils.isEmpty(element.getText())) {// 如果没有子元素,只有一个值 | |
| 134 | + json.put(element.getName(), element.getText()); | |
| 135 | + } | |
| 136 | + | |
| 137 | + for (Element e : chdEl) { // 有子元素 | |
| 138 | + if (!e.elements().isEmpty()) { // 子元素也有子元素 | |
| 139 | + JSONObject chdjson = new JSONObject(); | |
| 140 | + node2Json(e, chdjson); | |
| 141 | + Object o = json.get(e.getName()); | |
| 142 | + if (o != null) { | |
| 143 | + JSONArray jsona = null; | |
| 144 | + if (o instanceof JSONObject) { // 如果此元素已存在,则转为jsonArray | |
| 145 | + JSONObject jsono = (JSONObject) o; | |
| 146 | + json.remove(e.getName()); | |
| 147 | + jsona = new JSONArray(); | |
| 148 | + jsona.add(jsono); | |
| 149 | + jsona.add(chdjson); | |
| 150 | + } | |
| 151 | + if (o instanceof JSONArray) { | |
| 152 | + jsona = (JSONArray) o; | |
| 153 | + jsona.add(chdjson); | |
| 154 | + } | |
| 155 | + json.put(e.getName(), jsona); | |
| 156 | + } else { | |
| 157 | + if (!chdjson.isEmpty()) { | |
| 158 | + json.put(e.getName(), chdjson); | |
| 159 | + } | |
| 160 | + } | |
| 161 | + } else { // 子元素没有子元素 | |
| 162 | + for (Object o : element.attributes()) { | |
| 163 | + Attribute attr = (Attribute) o; | |
| 164 | + if (!ObjectUtils.isEmpty(attr.getValue())) { | |
| 165 | + json.put("@" + attr.getName(), attr.getValue()); | |
| 166 | + } | |
| 167 | + } | |
| 168 | + if (!e.getText().isEmpty()) { | |
| 169 | + json.put(e.getName(), e.getText()); | |
| 170 | + } | |
| 171 | + } | |
| 172 | + } | |
| 173 | + } | |
| 174 | + public static Element getRootElement(RequestEvent evt) throws DocumentException { | |
| 175 | + | |
| 176 | + return getRootElement(evt, "gb2312"); | |
| 177 | + } | |
| 178 | + | |
| 179 | + public static Element getRootElement(RequestEvent evt, String charset) throws DocumentException { | |
| 180 | + Request request = evt.getRequest(); | |
| 181 | + return getRootElement(request.getRawContent(), charset); | |
| 182 | + } | |
| 183 | + | |
| 184 | + public static Element getRootElement(byte[] content, String charset) throws DocumentException { | |
| 185 | + if (charset == null) { | |
| 186 | + charset = "gb2312"; | |
| 187 | + } | |
| 188 | + SAXReader reader = new SAXReader(); | |
| 189 | + reader.setEncoding(charset); | |
| 190 | + Document xml = reader.read(new ByteArrayInputStream(content)); | |
| 191 | + return xml.getRootElement(); | |
| 192 | + } | |
| 193 | + | |
| 194 | + private enum ChannelType{ | |
| 195 | + CivilCode, BusinessGroup,VirtualOrganization,Other | |
| 196 | + } | |
| 197 | + | |
| 198 | + public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event, CivilCodeFileConf civilCodeFileConf){ | |
| 199 | + DeviceChannel deviceChannel = new DeviceChannel(); | |
| 200 | + deviceChannel.setDeviceId(device.getDeviceId()); | |
| 201 | + Element channdelIdElement = itemDevice.element("DeviceID"); | |
| 202 | + if (channdelIdElement == null) { | |
| 203 | + logger.warn("解析Catalog消息时发现缺少 DeviceID"); | |
| 204 | + return null; | |
| 205 | + } | |
| 206 | + String channelId = channdelIdElement.getTextTrim(); | |
| 207 | + if (ObjectUtils.isEmpty(channelId)) { | |
| 208 | + logger.warn("解析Catalog消息时发现缺少 DeviceID"); | |
| 209 | + return null; | |
| 210 | + } | |
| 211 | + deviceChannel.setChannelId(channelId); | |
| 212 | + if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) { | |
| 213 | + // 除了ADD和update情况下需要识别全部内容, | |
| 214 | + return deviceChannel; | |
| 215 | + } | |
| 216 | + Element nameElement = itemDevice.element("Name"); | |
| 217 | + if (nameElement != null) { | |
| 218 | + deviceChannel.setName(nameElement.getText()); | |
| 219 | + } | |
| 220 | + if(channelId.length() <= 8) { | |
| 221 | + deviceChannel.setHasAudio(false); | |
| 222 | + CivilCodePo parentCode = civilCodeFileConf.getParentCode(channelId); | |
| 223 | + if (parentCode != null) { | |
| 224 | + deviceChannel.setParentId(parentCode.getCode()); | |
| 225 | + deviceChannel.setCivilCode(parentCode.getCode()); | |
| 226 | + }else { | |
| 227 | + logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId); | |
| 228 | + } | |
| 229 | + deviceChannel.setStatus(true); | |
| 230 | + return deviceChannel; | |
| 231 | + }else { | |
| 232 | + if(channelId.length() != 20) { | |
| 233 | + logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId); | |
| 234 | + return null; | |
| 235 | + } | |
| 236 | + | |
| 237 | + int code = Integer.parseInt(channelId.substring(10, 13)); | |
| 238 | + if (code == 136 || code == 137 || code == 138) { | |
| 239 | + deviceChannel.setHasAudio(true); | |
| 240 | + }else { | |
| 241 | + deviceChannel.setHasAudio(false); | |
| 242 | + } | |
| 243 | + // 设备厂商 | |
| 244 | + String manufacturer = getText(itemDevice, "Manufacturer"); | |
| 245 | + // 设备型号 | |
| 246 | + String model = getText(itemDevice, "Model"); | |
| 247 | + // 设备归属 | |
| 248 | + String owner = getText(itemDevice, "Owner"); | |
| 249 | + // 行政区域 | |
| 250 | + String civilCode = getText(itemDevice, "CivilCode"); | |
| 251 | + // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织 | |
| 252 | + String businessGroupID = getText(itemDevice, "BusinessGroupID"); | |
| 253 | + // 父设备/区域/系统ID | |
| 254 | + String parentID = getText(itemDevice, "ParentID"); | |
| 255 | + if (parentID != null && parentID.equalsIgnoreCase("null")) { | |
| 256 | + parentID = null; | |
| 257 | + } | |
| 258 | + // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式 | |
| 259 | + String registerWay = getText(itemDevice, "RegisterWay"); | |
| 260 | + // 保密属性(必选)缺省为0;0:不涉密,1:涉密 | |
| 261 | + String secrecy = getText(itemDevice, "Secrecy"); | |
| 262 | + // 安装地址 | |
| 263 | + String address = getText(itemDevice, "Address"); | |
| 264 | + | |
| 265 | + switch (code){ | |
| 266 | + case 200: | |
| 267 | + // 系统目录 | |
| 268 | + if (!ObjectUtils.isEmpty(manufacturer)) { | |
| 269 | + deviceChannel.setManufacture(manufacturer); | |
| 270 | + } | |
| 271 | + if (!ObjectUtils.isEmpty(model)) { | |
| 272 | + deviceChannel.setModel(model); | |
| 273 | + } | |
| 274 | + if (!ObjectUtils.isEmpty(owner)) { | |
| 275 | + deviceChannel.setOwner(owner); | |
| 276 | + } | |
| 277 | + if (!ObjectUtils.isEmpty(civilCode)) { | |
| 278 | + deviceChannel.setCivilCode(civilCode); | |
| 279 | + deviceChannel.setParentId(civilCode); | |
| 280 | + }else { | |
| 281 | + if (!ObjectUtils.isEmpty(parentID)) { | |
| 282 | + deviceChannel.setParentId(parentID); | |
| 283 | + } | |
| 284 | + } | |
| 285 | + if (!ObjectUtils.isEmpty(address)) { | |
| 286 | + deviceChannel.setAddress(address); | |
| 287 | + } | |
| 288 | + deviceChannel.setStatus(true); | |
| 289 | + if (!ObjectUtils.isEmpty(registerWay)) { | |
| 290 | + try { | |
| 291 | + deviceChannel.setRegisterWay(Integer.parseInt(registerWay)); | |
| 292 | + }catch (NumberFormatException exception) { | |
| 293 | + logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); | |
| 294 | + } | |
| 295 | + } | |
| 296 | + if (!ObjectUtils.isEmpty(secrecy)) { | |
| 297 | + deviceChannel.setSecrecy(secrecy); | |
| 298 | + } | |
| 299 | + return deviceChannel; | |
| 300 | + case 215: | |
| 301 | + // 业务分组 | |
| 302 | + deviceChannel.setStatus(true); | |
| 303 | + if (!ObjectUtils.isEmpty(parentID)) { | |
| 304 | + if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) { | |
| 305 | + deviceChannel.setParentId(parentID); | |
| 306 | + } | |
| 307 | + }else { | |
| 308 | + logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId"); | |
| 309 | + if (!ObjectUtils.isEmpty(civilCode)) { | |
| 310 | + deviceChannel.setCivilCode(civilCode); | |
| 311 | + } | |
| 312 | + } | |
| 313 | + break; | |
| 314 | + case 216: | |
| 315 | + // 虚拟组织 | |
| 316 | + deviceChannel.setStatus(true); | |
| 317 | + if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 318 | + deviceChannel.setBusinessGroupId(businessGroupID); | |
| 319 | + } | |
| 320 | + | |
| 321 | + if (!ObjectUtils.isEmpty(parentID)) { | |
| 322 | + if (parentID.contains("/")) { | |
| 323 | + String[] parentIdArray = parentID.split("/"); | |
| 324 | + parentID = parentIdArray[parentIdArray.length - 1]; | |
| 325 | + } | |
| 326 | + deviceChannel.setParentId(parentID); | |
| 327 | + }else { | |
| 328 | + if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 329 | + deviceChannel.setParentId(businessGroupID); | |
| 330 | + } | |
| 331 | + } | |
| 332 | + break; | |
| 333 | + default: | |
| 334 | + // 设备目录 | |
| 335 | + if (!ObjectUtils.isEmpty(manufacturer)) { | |
| 336 | + deviceChannel.setManufacture(manufacturer); | |
| 337 | + } | |
| 338 | + if (!ObjectUtils.isEmpty(model)) { | |
| 339 | + deviceChannel.setModel(model); | |
| 340 | + } | |
| 341 | + if (!ObjectUtils.isEmpty(owner)) { | |
| 342 | + deviceChannel.setOwner(owner); | |
| 343 | + } | |
| 344 | + if (!ObjectUtils.isEmpty(civilCode) | |
| 345 | + && civilCode.length() <= 8 | |
| 346 | + && NumberUtils.isParsable(civilCode) | |
| 347 | + && civilCode.length()%2 == 0 | |
| 348 | + ) { | |
| 349 | + deviceChannel.setCivilCode(civilCode); | |
| 350 | + } | |
| 351 | + if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 352 | + deviceChannel.setBusinessGroupId(businessGroupID); | |
| 353 | + } | |
| 354 | + | |
| 355 | + // 警区 | |
| 356 | + String block = getText(itemDevice, "Block"); | |
| 357 | + if (!ObjectUtils.isEmpty(block)) { | |
| 358 | + deviceChannel.setBlock(block); | |
| 359 | + } | |
| 360 | + if (!ObjectUtils.isEmpty(address)) { | |
| 361 | + deviceChannel.setAddress(address); | |
| 362 | + } | |
| 363 | + | |
| 364 | + if (!ObjectUtils.isEmpty(secrecy)) { | |
| 365 | + deviceChannel.setSecrecy(secrecy); | |
| 366 | + } | |
| 367 | + | |
| 368 | + // 当为设备时,是否有子设备(必选)1有,0没有 | |
| 369 | + String parental = getText(itemDevice, "Parental"); | |
| 370 | + if (!ObjectUtils.isEmpty(parental)) { | |
| 371 | + try { | |
| 372 | + // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 | |
| 373 | + if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) { | |
| 374 | + deviceChannel.setParental(0); | |
| 375 | + }else { | |
| 376 | + deviceChannel.setParental(1); | |
| 377 | + } | |
| 378 | + }catch (NumberFormatException e) { | |
| 379 | + logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental); | |
| 380 | + } | |
| 381 | + } | |
| 382 | + // 父设备/区域/系统ID | |
| 383 | + | |
| 384 | + if (!ObjectUtils.isEmpty(parentID) ) { | |
| 385 | + if (parentID.contains("/")) { | |
| 386 | + String[] parentIdArray = parentID.split("/"); | |
| 387 | + deviceChannel.setParentId(parentIdArray[parentIdArray.length - 1]); | |
| 388 | + }else { | |
| 389 | + if (parentID.length()%2 == 0) { | |
| 390 | + deviceChannel.setParentId(parentID); | |
| 391 | + }else { | |
| 392 | + logger.warn("[xml解析] 不规范的parentID:{}, 已舍弃", parentID); | |
| 393 | + } | |
| 394 | + } | |
| 395 | + }else { | |
| 396 | + if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 397 | + deviceChannel.setParentId(businessGroupID); | |
| 398 | + }else { | |
| 399 | + if (!ObjectUtils.isEmpty(deviceChannel.getCivilCode())) { | |
| 400 | + deviceChannel.setParentId(deviceChannel.getCivilCode()); | |
| 401 | + } | |
| 402 | + } | |
| 403 | + } | |
| 404 | + // 注册方式 | |
| 405 | + if (!ObjectUtils.isEmpty(registerWay)) { | |
| 406 | + try { | |
| 407 | + int registerWayInt = Integer.parseInt(registerWay); | |
| 408 | + deviceChannel.setRegisterWay(registerWayInt); | |
| 409 | + }catch (NumberFormatException exception) { | |
| 410 | + logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); | |
| 411 | + deviceChannel.setRegisterWay(1); | |
| 412 | + } | |
| 413 | + }else { | |
| 414 | + deviceChannel.setRegisterWay(1); | |
| 415 | + } | |
| 416 | + | |
| 417 | + // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式 | |
| 418 | + String safetyWay = getText(itemDevice, "SafetyWay"); | |
| 419 | + if (!ObjectUtils.isEmpty(safetyWay)) { | |
| 420 | + try { | |
| 421 | + deviceChannel.setSafetyWay(Integer.parseInt(safetyWay)); | |
| 422 | + }catch (NumberFormatException e) { | |
| 423 | + logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay); | |
| 424 | + } | |
| 425 | + } | |
| 426 | + | |
| 427 | + // 证书序列号(有证书的设备必选) | |
| 428 | + String certNum = getText(itemDevice, "CertNum"); | |
| 429 | + if (!ObjectUtils.isEmpty(certNum)) { | |
| 430 | + deviceChannel.setCertNum(certNum); | |
| 431 | + } | |
| 432 | + | |
| 433 | + // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效 | |
| 434 | + String certifiable = getText(itemDevice, "Certifiable"); | |
| 435 | + if (!ObjectUtils.isEmpty(certifiable)) { | |
| 436 | + try { | |
| 437 | + deviceChannel.setCertifiable(Integer.parseInt(certifiable)); | |
| 438 | + }catch (NumberFormatException e) { | |
| 439 | + logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable); | |
| 440 | + } | |
| 441 | + } | |
| 442 | + | |
| 443 | + // 无效原因码(有证书且证书无效的设备必选) | |
| 444 | + String errCode = getText(itemDevice, "ErrCode"); | |
| 445 | + if (!ObjectUtils.isEmpty(errCode)) { | |
| 446 | + try { | |
| 447 | + deviceChannel.setErrCode(Integer.parseInt(errCode)); | |
| 448 | + }catch (NumberFormatException e) { | |
| 449 | + logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode); | |
| 450 | + } | |
| 451 | + } | |
| 452 | + | |
| 453 | + // 证书终止有效期(有证书的设备必选) | |
| 454 | + String endTime = getText(itemDevice, "EndTime"); | |
| 455 | + if (!ObjectUtils.isEmpty(endTime)) { | |
| 456 | + deviceChannel.setEndTime(endTime); | |
| 457 | + } | |
| 458 | + | |
| 459 | + | |
| 460 | + // 设备/区域/系统IP地址 | |
| 461 | + String ipAddress = getText(itemDevice, "IPAddress"); | |
| 462 | + if (!ObjectUtils.isEmpty(ipAddress)) { | |
| 463 | + deviceChannel.setIpAddress(ipAddress); | |
| 464 | + } | |
| 465 | + | |
| 466 | + // 设备/区域/系统端口 | |
| 467 | + String port = getText(itemDevice, "Port"); | |
| 468 | + if (!ObjectUtils.isEmpty(port)) { | |
| 469 | + try { | |
| 470 | + deviceChannel.setPort(Integer.parseInt(port)); | |
| 471 | + }catch (NumberFormatException e) { | |
| 472 | + logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port); | |
| 473 | + } | |
| 474 | + } | |
| 475 | + | |
| 476 | + // 设备口令 | |
| 477 | + String password = getText(itemDevice, "Password"); | |
| 478 | + if (!ObjectUtils.isEmpty(password)) { | |
| 479 | + deviceChannel.setPassword(password); | |
| 480 | + } | |
| 481 | + | |
| 482 | + | |
| 483 | + // 设备状态 | |
| 484 | + String status = getText(itemDevice, "Status"); | |
| 485 | + if (status != null) { | |
| 486 | + // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 | |
| 487 | + if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) { | |
| 488 | + deviceChannel.setStatus(true); | |
| 489 | + } | |
| 490 | + if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { | |
| 491 | + deviceChannel.setStatus(false); | |
| 492 | + } | |
| 493 | + }else { | |
| 494 | + deviceChannel.setStatus(true); | |
| 495 | + } | |
| 496 | + | |
| 497 | + // 经度 | |
| 498 | + String longitude = getText(itemDevice, "Longitude"); | |
| 499 | + if (NumericUtil.isDouble(longitude)) { | |
| 500 | + deviceChannel.setLongitude(Double.parseDouble(longitude)); | |
| 501 | + } else { | |
| 502 | + deviceChannel.setLongitude(0.00); | |
| 503 | + } | |
| 504 | + | |
| 505 | + // 纬度 | |
| 506 | + String latitude = getText(itemDevice, "Latitude"); | |
| 507 | + if (NumericUtil.isDouble(latitude)) { | |
| 508 | + deviceChannel.setLatitude(Double.parseDouble(latitude)); | |
| 509 | + } else { | |
| 510 | + deviceChannel.setLatitude(0.00); | |
| 511 | + } | |
| 512 | + | |
| 513 | + deviceChannel.setGpsTime(DateUtil.getNow()); | |
| 514 | + | |
| 515 | + // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选 | |
| 516 | + String ptzType = getText(itemDevice, "PTZType"); | |
| 517 | + if (ObjectUtils.isEmpty(ptzType)) { | |
| 518 | + //兼容INFO中的信息 | |
| 519 | + Element info = itemDevice.element("Info"); | |
| 520 | + String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType"); | |
| 521 | + if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){ | |
| 522 | + try { | |
| 523 | + deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo)); | |
| 524 | + }catch (NumberFormatException e){ | |
| 525 | + logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo); | |
| 526 | + } | |
| 527 | + } | |
| 528 | + } else { | |
| 529 | + try { | |
| 530 | + deviceChannel.setPTZType(Integer.parseInt(ptzType)); | |
| 531 | + }catch (NumberFormatException e){ | |
| 532 | + logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType); | |
| 533 | + } | |
| 534 | + } | |
| 535 | + | |
| 536 | + // TODO 摄像机位置类型扩展。 | |
| 537 | + // 1-省际检查站、 | |
| 538 | + // 2-党政机关、 | |
| 539 | + // 3-车站码头、 | |
| 540 | + // 4-中心广场、 | |
| 541 | + // 5-体育场馆、 | |
| 542 | + // 6-商业中心、 | |
| 543 | + // 7-宗教场所、 | |
| 544 | + // 8-校园周边、 | |
| 545 | + // 9-治安复杂区域、 | |
| 546 | + // 10-交通干线。 | |
| 547 | + // String positionType = getText(itemDevice, "PositionType"); | |
| 548 | + | |
| 549 | + // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。 | |
| 550 | + // String roomType = getText(itemDevice, "RoomType"); | |
| 551 | + // TODO 摄像机用途属性 | |
| 552 | + // String useType = getText(itemDevice, "UseType"); | |
| 553 | + // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光 | |
| 554 | + // String supplyLightType = getText(itemDevice, "SupplyLightType"); | |
| 555 | + // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。 | |
| 556 | + // String directionType = getText(itemDevice, "DirectionType"); | |
| 557 | + // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定 | |
| 558 | + // String resolution = getText(itemDevice, "Resolution"); | |
| 559 | + | |
| 560 | + // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4 | |
| 561 | + // String downloadSpeed = getText(itemDevice, "DownloadSpeed"); | |
| 562 | + // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层) | |
| 563 | + // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode"); | |
| 564 | + // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强 | |
| 565 | + // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode"); | |
| 566 | + | |
| 567 | + | |
| 568 | + deviceChannel.setSecrecy(secrecy); | |
| 569 | + break; | |
| 570 | + } | |
| 571 | + } | |
| 572 | + | |
| 573 | + return deviceChannel; | |
| 574 | + } | |
| 575 | + | |
| 576 | + /** | |
| 577 | + * 新增方法支持内部嵌套 | |
| 578 | + * | |
| 579 | + * @param element xmlElement | |
| 580 | + * @param clazz 结果类 | |
| 581 | + * @param <T> 泛型 | |
| 582 | + * @return 结果对象 | |
| 583 | + * @throws NoSuchMethodException | |
| 584 | + * @throws InvocationTargetException | |
| 585 | + * @throws InstantiationException | |
| 586 | + * @throws IllegalAccessException | |
| 587 | + */ | |
| 588 | + public static <T> T loadElement(Element element, Class<T> clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { | |
| 589 | + Field[] fields = clazz.getDeclaredFields(); | |
| 590 | + T t = clazz.getDeclaredConstructor().newInstance(); | |
| 591 | + for (Field field : fields) { | |
| 592 | + ReflectionUtils.makeAccessible(field); | |
| 593 | + MessageElement annotation = field.getAnnotation(MessageElement.class); | |
| 594 | + if (annotation == null) { | |
| 595 | + continue; | |
| 596 | + } | |
| 597 | + String value = annotation.value(); | |
| 598 | + String subVal = annotation.subVal(); | |
| 599 | + Element element1 = element.element(value); | |
| 600 | + if (element1 == null) { | |
| 601 | + continue; | |
| 602 | + } | |
| 603 | + if ("".equals(subVal)) { | |
| 604 | + // 无下级数据 | |
| 605 | + Object fieldVal = element1.isTextOnly() ? element1.getText() : loadElement(element1, field.getType()); | |
| 606 | + Object o = simpleTypeDeal(field.getType(), fieldVal); | |
| 607 | + ReflectionUtils.setField(field, t, o); | |
| 608 | + } else { | |
| 609 | + // 存在下级数据 | |
| 610 | + ArrayList<Object> list = new ArrayList<>(); | |
| 611 | + Type genericType = field.getGenericType(); | |
| 612 | + if (!(genericType instanceof ParameterizedType)) { | |
| 613 | + continue; | |
| 614 | + } | |
| 615 | + Class<?> aClass = (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0]; | |
| 616 | + for (Element element2 : element1.elements(subVal)) { | |
| 617 | + list.add(loadElement(element2, aClass)); | |
| 618 | + } | |
| 619 | + ReflectionUtils.setField(field, t, list); | |
| 620 | + } | |
| 621 | + } | |
| 622 | + return t; | |
| 623 | + } | |
| 624 | + | |
| 625 | + /** | |
| 626 | + * 简单类型处理 | |
| 627 | + * | |
| 628 | + * @param tClass | |
| 629 | + * @param val | |
| 630 | + * @return | |
| 631 | + */ | |
| 632 | + private static Object simpleTypeDeal(Class<?> tClass, Object val) { | |
| 633 | + if (tClass.equals(String.class)) { | |
| 634 | + return val.toString(); | |
| 635 | + } | |
| 636 | + if (tClass.equals(Integer.class)) { | |
| 637 | + return Integer.valueOf(val.toString()); | |
| 638 | + } | |
| 639 | + if (tClass.equals(Double.class)) { | |
| 640 | + return Double.valueOf(val.toString()); | |
| 641 | + } | |
| 642 | + if (tClass.equals(Long.class)) { | |
| 643 | + return Long.valueOf(val.toString()); | |
| 644 | + } | |
| 645 | + return val; | |
| 646 | + } | |
| 647 | 647 | } |
| 648 | 648 | \ No newline at end of file | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
| ... | ... | @@ -21,6 +21,7 @@ public class AssistRESTfulUtils { |
| 21 | 21 | |
| 22 | 22 | private final static Logger logger = LoggerFactory.getLogger(AssistRESTfulUtils.class); |
| 23 | 23 | |
| 24 | + | |
| 24 | 25 | public interface RequestCallback{ |
| 25 | 26 | void run(JSONObject response); |
| 26 | 27 | } |
| ... | ... | @@ -145,4 +146,25 @@ public class AssistRESTfulUtils { |
| 145 | 146 | return sendGet(mediaServerItem, "api/record/addStreamCallInfo",param, callback); |
| 146 | 147 | } |
| 147 | 148 | |
| 149 | + public JSONObject getDateList(MediaServerItem mediaServerItem, String app, String stream, int year, int month) { | |
| 150 | + Map<String, Object> param = new HashMap<>(); | |
| 151 | + param.put("app", app); | |
| 152 | + param.put("stream", stream); | |
| 153 | + param.put("year", year); | |
| 154 | + param.put("month", month); | |
| 155 | + return sendGet(mediaServerItem, "api/record/date/list", param, null); | |
| 156 | + } | |
| 157 | + | |
| 158 | + public JSONObject getFileList(MediaServerItem mediaServerItem, int page, int count, String app, String stream, | |
| 159 | + String startTime, String endTime) { | |
| 160 | + Map<String, Object> param = new HashMap<>(); | |
| 161 | + param.put("app", app); | |
| 162 | + param.put("stream", stream); | |
| 163 | + param.put("page", page); | |
| 164 | + param.put("count", count); | |
| 165 | + param.put("startTime", startTime); | |
| 166 | + param.put("endTime", endTime); | |
| 167 | + return sendGet(mediaServerItem, "api/record/file/listWithDate", param, null); | |
| 168 | + } | |
| 169 | + | |
| 148 | 170 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.media.zlm; | |
| 2 | - | |
| 3 | -import com.alibaba.fastjson2.JSON; | |
| 4 | -import com.alibaba.fastjson2.JSONObject; | |
| 5 | -import com.genersoft.iot.vmp.common.InviteInfo; | |
| 6 | -import com.genersoft.iot.vmp.common.InviteSessionType; | |
| 7 | -import com.genersoft.iot.vmp.common.StreamInfo; | |
| 8 | -import com.genersoft.iot.vmp.common.VideoManagerConstants; | |
| 9 | -import com.genersoft.iot.vmp.conf.UserSetting; | |
| 10 | -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | |
| 11 | -import com.genersoft.iot.vmp.gb28181.bean.*; | |
| 12 | -import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | |
| 13 | -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | |
| 14 | -import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; | |
| 15 | -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 16 | -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | |
| 17 | -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | |
| 18 | -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | |
| 19 | -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; | |
| 20 | -import com.genersoft.iot.vmp.media.zlm.dto.HookType; | |
| 21 | -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 22 | -import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; | |
| 23 | -import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; | |
| 24 | -import com.genersoft.iot.vmp.media.zlm.dto.hook.*; | |
| 25 | -import com.genersoft.iot.vmp.service.*; | |
| 26 | -import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; | |
| 27 | -import com.genersoft.iot.vmp.service.bean.SSRCInfo; | |
| 28 | -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 29 | -import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | |
| 30 | -import com.genersoft.iot.vmp.utils.DateUtil; | |
| 31 | -import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | |
| 32 | -import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo; | |
| 33 | -import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo; | |
| 34 | -import com.genersoft.iot.vmp.vmanager.bean.StreamContent; | |
| 35 | -import org.slf4j.Logger; | |
| 36 | -import org.slf4j.LoggerFactory; | |
| 37 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 38 | -import org.springframework.beans.factory.annotation.Qualifier; | |
| 39 | -import org.springframework.data.redis.core.RedisTemplate; | |
| 40 | -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | |
| 41 | -import org.springframework.util.ObjectUtils; | |
| 42 | -import org.springframework.web.bind.annotation.*; | |
| 43 | -import org.springframework.web.context.request.async.DeferredResult; | |
| 44 | - | |
| 45 | -import javax.servlet.http.HttpServletRequest; | |
| 46 | -import javax.sip.InvalidArgumentException; | |
| 47 | -import javax.sip.SipException; | |
| 48 | -import java.text.ParseException; | |
| 49 | -import java.util.HashMap; | |
| 50 | -import java.util.List; | |
| 51 | -import java.util.Map; | |
| 52 | -import java.util.UUID; | |
| 53 | - | |
| 54 | -/** | |
| 55 | - * @description:针对 ZLMediaServer的hook事件监听 | |
| 56 | - * @author: swwheihei | |
| 57 | - * @date: 2020年5月8日 上午10:46:48 | |
| 58 | - */ | |
| 59 | -@RestController | |
| 60 | -@RequestMapping("/index/hook") | |
| 61 | -public class ZLMHttpHookListener { | |
| 62 | - | |
| 63 | - private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class); | |
| 64 | - | |
| 65 | - @Autowired | |
| 66 | - private SIPCommander cmder; | |
| 67 | - | |
| 68 | - @Autowired | |
| 69 | - private SIPCommanderFroPlatform commanderFroPlatform; | |
| 70 | - | |
| 71 | - @Autowired | |
| 72 | - private IPlayService playService; | |
| 73 | - | |
| 74 | - @Autowired | |
| 75 | - private IVideoManagerStorage storager; | |
| 76 | - | |
| 77 | - @Autowired | |
| 78 | - private IRedisCatchStorage redisCatchStorage; | |
| 79 | - | |
| 80 | - @Autowired | |
| 81 | - private IInviteStreamService inviteStreamService; | |
| 82 | - | |
| 83 | - @Autowired | |
| 84 | - private IDeviceService deviceService; | |
| 85 | - | |
| 86 | - @Autowired | |
| 87 | - private IMediaServerService mediaServerService; | |
| 88 | - | |
| 89 | - @Autowired | |
| 90 | - private IStreamProxyService streamProxyService; | |
| 91 | - | |
| 92 | - @Autowired | |
| 93 | - private DeferredResultHolder resultHolder; | |
| 94 | - | |
| 95 | - @Autowired | |
| 96 | - private IMediaService mediaService; | |
| 97 | - | |
| 98 | - @Autowired | |
| 99 | - private EventPublisher eventPublisher; | |
| 100 | - | |
| 101 | - @Autowired | |
| 102 | - private ZLMMediaListManager zlmMediaListManager; | |
| 103 | - | |
| 104 | - @Autowired | |
| 105 | - private ZlmHttpHookSubscribe subscribe; | |
| 106 | - | |
| 107 | - @Autowired | |
| 108 | - private UserSetting userSetting; | |
| 109 | - | |
| 110 | - @Autowired | |
| 111 | - private IUserService userService; | |
| 112 | - | |
| 113 | - @Autowired | |
| 114 | - private VideoStreamSessionManager sessionManager; | |
| 115 | - | |
| 116 | - @Autowired | |
| 117 | - private AssistRESTfulUtils assistRESTfulUtils; | |
| 118 | - | |
| 119 | - @Autowired | |
| 120 | - private SSRCFactory ssrcFactory; | |
| 121 | - | |
| 122 | - @Qualifier("taskExecutor") | |
| 123 | - @Autowired | |
| 124 | - private ThreadPoolTaskExecutor taskExecutor; | |
| 125 | - | |
| 126 | - @Autowired | |
| 127 | - private RedisTemplate<Object, Object> redisTemplate; | |
| 128 | - | |
| 129 | - /** | |
| 130 | - * 服务器定时上报时间,上报间隔可配置,默认10s上报一次 | |
| 131 | - */ | |
| 132 | - @ResponseBody | |
| 133 | - | |
| 134 | - @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8") | |
| 135 | - public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) { | |
| 136 | - | |
| 137 | - | |
| 138 | - taskExecutor.execute(() -> { | |
| 139 | - List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive); | |
| 140 | - if (subscribes != null && subscribes.size() > 0) { | |
| 141 | - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | |
| 142 | - subscribe.response(null, param); | |
| 143 | - } | |
| 144 | - } | |
| 145 | - }); | |
| 146 | - mediaServerService.updateMediaServerKeepalive(param.getMediaServerId(), param.getData()); | |
| 147 | - | |
| 148 | - return HookResult.SUCCESS(); | |
| 149 | - } | |
| 150 | - | |
| 151 | - /** | |
| 152 | - * 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。 | |
| 153 | - */ | |
| 154 | - @ResponseBody | |
| 155 | - | |
| 156 | - @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8") | |
| 157 | - public HookResult onPlay(@RequestBody OnPlayHookParam param) { | |
| 158 | - if (logger.isDebugEnabled()) { | |
| 159 | - logger.debug("[ZLM HOOK] 播放鉴权:{}->{}" + param.getMediaServerId(), param); | |
| 160 | - } | |
| 161 | - String mediaServerId = param.getMediaServerId(); | |
| 162 | - | |
| 163 | - taskExecutor.execute(() -> { | |
| 164 | - JSONObject json = (JSONObject) JSON.toJSON(param); | |
| 165 | - ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json); | |
| 166 | - if (subscribe != null) { | |
| 167 | - MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); | |
| 168 | - if (mediaInfo != null) { | |
| 169 | - subscribe.response(mediaInfo, param); | |
| 170 | - } | |
| 171 | - } | |
| 172 | - }); | |
| 173 | - if (!"rtp".equals(param.getApp())) { | |
| 174 | - Map<String, String> paramMap = urlParamToMap(param.getParams()); | |
| 175 | - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | |
| 176 | - if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) { | |
| 177 | - return new HookResult(401, "Unauthorized"); | |
| 178 | - } | |
| 179 | - } | |
| 180 | - | |
| 181 | - return HookResult.SUCCESS(); | |
| 182 | - } | |
| 183 | - | |
| 184 | - /** | |
| 185 | - * rtsp/rtmp/rtp推流鉴权事件。 | |
| 186 | - */ | |
| 187 | - @ResponseBody | |
| 188 | - @PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8") | |
| 189 | - public HookResultForOnPublish onPublish(@RequestBody OnPublishHookParam param) { | |
| 190 | - | |
| 191 | - JSONObject json = (JSONObject) JSON.toJSON(param); | |
| 192 | - | |
| 193 | - logger.info("[ZLM HOOK]推流鉴权:{}->{}", param.getMediaServerId(), param); | |
| 194 | - | |
| 195 | - String mediaServerId = json.getString("mediaServerId"); | |
| 196 | - MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); | |
| 197 | - if (mediaInfo == null) { | |
| 198 | - return new HookResultForOnPublish(200, "success"); | |
| 199 | - } | |
| 200 | - // 推流鉴权的处理 | |
| 201 | - if (!"rtp".equals(param.getApp())) { | |
| 202 | - if (userSetting.getPushAuthority()) { | |
| 203 | - // 推流鉴权 | |
| 204 | - if (param.getParams() == null) { | |
| 205 | - logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)"); | |
| 206 | - return new HookResultForOnPublish(401, "Unauthorized"); | |
| 207 | - } | |
| 208 | - Map<String, String> paramMap = urlParamToMap(param.getParams()); | |
| 209 | - String sign = paramMap.get("sign"); | |
| 210 | - if (sign == null) { | |
| 211 | - logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)"); | |
| 212 | - return new HookResultForOnPublish(401, "Unauthorized"); | |
| 213 | - } | |
| 214 | - // 推流自定义播放鉴权码 | |
| 215 | - String callId = paramMap.get("callId"); | |
| 216 | - // 鉴权配置 | |
| 217 | - boolean hasAuthority = userService.checkPushAuthority(callId, sign); | |
| 218 | - if (!hasAuthority) { | |
| 219 | - logger.info("推流鉴权失败: sign 无权限: callId={}. sign={}", callId, sign); | |
| 220 | - return new HookResultForOnPublish(401, "Unauthorized"); | |
| 221 | - } | |
| 222 | - StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); | |
| 223 | - streamAuthorityInfo.setCallId(callId); | |
| 224 | - streamAuthorityInfo.setSign(sign); | |
| 225 | - // 鉴权通过 | |
| 226 | - redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); | |
| 227 | - // 通知assist新的callId | |
| 228 | - if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) { | |
| 229 | - taskExecutor.execute(() -> { | |
| 230 | - assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null); | |
| 231 | - }); | |
| 232 | - } | |
| 233 | - } | |
| 234 | - } else { | |
| 235 | - zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId()); | |
| 236 | - } | |
| 237 | - | |
| 238 | - | |
| 239 | - HookResultForOnPublish result = HookResultForOnPublish.SUCCESS(); | |
| 240 | - result.setEnable_audio(true); | |
| 241 | - taskExecutor.execute(() -> { | |
| 242 | - ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json); | |
| 243 | - if (subscribe != null) { | |
| 244 | - if (mediaInfo != null) { | |
| 245 | - subscribe.response(mediaInfo, param); | |
| 246 | - } else { | |
| 247 | - new HookResultForOnPublish(1, "zlm not register"); | |
| 248 | - } | |
| 249 | - } | |
| 250 | - }); | |
| 251 | - | |
| 252 | - // 是否录像 | |
| 253 | - if ("rtp".equals(param.getApp())) { | |
| 254 | - result.setEnable_mp4(userSetting.getRecordSip()); | |
| 255 | - } else { | |
| 256 | - result.setEnable_mp4(userSetting.isRecordPushLive()); | |
| 257 | - } | |
| 258 | - // 替换流地址 | |
| 259 | - if ("rtp".equals(param.getApp()) && !mediaInfo.isRtpEnable()) { | |
| 260 | - String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));; | |
| 261 | - InviteInfo inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc); | |
| 262 | - if (inviteInfo != null) { | |
| 263 | - result.setStream_replace(inviteInfo.getStream()); | |
| 264 | - logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream()); | |
| 265 | - } | |
| 266 | - } | |
| 267 | - List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream()); | |
| 268 | - if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { | |
| 269 | - String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); | |
| 270 | - String channelId = ssrcTransactionForAll.get(0).getChannelId(); | |
| 271 | - DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); | |
| 272 | - if (deviceChannel != null) { | |
| 273 | - result.setEnable_audio(deviceChannel.isHasAudio()); | |
| 274 | - } | |
| 275 | - // 如果是录像下载就设置视频间隔十秒 | |
| 276 | - if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) { | |
| 277 | - result.setMp4_max_second(10); | |
| 278 | - result.setEnable_mp4(true); | |
| 279 | - } | |
| 280 | - } | |
| 281 | - if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) { | |
| 282 | - logger.info("推流时发现尚未设置录像路径,从assist服务中读取"); | |
| 283 | - JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null); | |
| 284 | - if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) { | |
| 285 | - JSONObject dataJson = info.getJSONObject("data"); | |
| 286 | - if (dataJson != null) { | |
| 287 | - String recordPath = dataJson.getString("record"); | |
| 288 | - userSetting.setRecordPath(recordPath); | |
| 289 | - result.setMp4_save_path(recordPath); | |
| 290 | - // 修改zlm中的录像路径 | |
| 291 | - if (mediaInfo.isAutoConfig()) { | |
| 292 | - taskExecutor.execute(() -> { | |
| 293 | - mediaServerService.setZLMConfig(mediaInfo, false); | |
| 294 | - }); | |
| 295 | - } | |
| 296 | - } | |
| 297 | - } | |
| 298 | - } | |
| 299 | - if (param.getApp().equalsIgnoreCase("rtp")) { | |
| 300 | - String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + param.getStream(); | |
| 301 | - OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(receiveKey); | |
| 302 | - | |
| 303 | - String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + param.getStream(); | |
| 304 | - OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo)redisTemplate.opsForValue().get(receiveKeyForPS); | |
| 305 | - if (otherRtpSendInfo != null || otherPsSendInfo != null) { | |
| 306 | - result.setEnable_mp4(true); | |
| 307 | - } | |
| 308 | - } | |
| 309 | - logger.info("[ZLM HOOK]推流鉴权 响应:{}->{}->>>>{}", param.getMediaServerId(), param, result); | |
| 310 | - return result; | |
| 311 | - } | |
| 312 | - | |
| 313 | - | |
| 314 | - /** | |
| 315 | - * rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。 | |
| 316 | - */ | |
| 317 | - @ResponseBody | |
| 318 | - @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") | |
| 319 | - public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) { | |
| 320 | - | |
| 321 | - if (param.isRegist()) { | |
| 322 | - logger.info("[ZLM HOOK] 流注册, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | |
| 323 | - } else { | |
| 324 | - logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | |
| 325 | - } | |
| 326 | - | |
| 327 | - | |
| 328 | - JSONObject json = (JSONObject) JSON.toJSON(param); | |
| 329 | - taskExecutor.execute(() -> { | |
| 330 | - ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json); | |
| 331 | - MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); | |
| 332 | - if (mediaInfo == null) { | |
| 333 | - logger.info("[ZLM HOOK] 流变化未找到ZLM, {}", param.getMediaServerId()); | |
| 334 | - return; | |
| 335 | - } | |
| 336 | - if (subscribe != null) { | |
| 337 | - subscribe.response(mediaInfo, param); | |
| 338 | - } | |
| 339 | - | |
| 340 | - List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks(); | |
| 341 | - // TODO 重构此处逻辑 | |
| 342 | - boolean isPush = false; | |
| 343 | - if (param.isRegist()) { | |
| 344 | - // 处理流注册的鉴权信息 | |
| 345 | - if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | |
| 346 | - || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | |
| 347 | - || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | |
| 348 | - isPush = true; | |
| 349 | - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | |
| 350 | - if (streamAuthorityInfo == null) { | |
| 351 | - streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); | |
| 352 | - } else { | |
| 353 | - streamAuthorityInfo.setOriginType(param.getOriginType()); | |
| 354 | - streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr()); | |
| 355 | - } | |
| 356 | - redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); | |
| 357 | - } | |
| 358 | - } else { | |
| 359 | - redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream()); | |
| 360 | - } | |
| 361 | - | |
| 362 | - if ("rtsp".equals(param.getSchema())) { | |
| 363 | - // 更新流媒体负载信息 | |
| 364 | - if (param.isRegist()) { | |
| 365 | - mediaServerService.addCount(param.getMediaServerId()); | |
| 366 | - } else { | |
| 367 | - mediaServerService.removeCount(param.getMediaServerId()); | |
| 368 | - } | |
| 369 | - // 设置拉流代理上线/离线 | |
| 370 | - int updateStatusResult = streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream()); | |
| 371 | - if (updateStatusResult > 0) { | |
| 372 | - | |
| 373 | - } | |
| 374 | - | |
| 375 | - if ("rtp".equals(param.getApp()) && !param.isRegist()) { | |
| 376 | - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream()); | |
| 377 | - if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) { | |
| 378 | - inviteStreamService.removeInviteInfo(inviteInfo); | |
| 379 | - storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId()); | |
| 380 | - } | |
| 381 | - } else { | |
| 382 | - if (!"rtp".equals(param.getApp())) { | |
| 383 | - String type = OriginType.values()[param.getOriginType()].getType(); | |
| 384 | - if (param.isRegist()) { | |
| 385 | - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo( | |
| 386 | - param.getApp(), param.getStream()); | |
| 387 | - String callId = null; | |
| 388 | - if (streamAuthorityInfo != null) { | |
| 389 | - callId = streamAuthorityInfo.getCallId(); | |
| 390 | - } | |
| 391 | - StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo, | |
| 392 | - param.getApp(), param.getStream(), tracks, callId); | |
| 393 | - param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); | |
| 394 | - redisCatchStorage.addStream(mediaInfo, type, param.getApp(), param.getStream(), param); | |
| 395 | - if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | |
| 396 | - || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | |
| 397 | - || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | |
| 398 | - param.setSeverId(userSetting.getServerId()); | |
| 399 | - zlmMediaListManager.addPush(param); | |
| 400 | - } | |
| 401 | - } else { | |
| 402 | - // 兼容流注销时类型从redis记录获取 | |
| 403 | - OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo( | |
| 404 | - param.getApp(), param.getStream(), param.getMediaServerId()); | |
| 405 | - if (onStreamChangedHookParam != null) { | |
| 406 | - type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType(); | |
| 407 | - redisCatchStorage.removeStream(mediaInfo.getId(), type, param.getApp(), param.getStream()); | |
| 408 | - } | |
| 409 | - GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); | |
| 410 | - if (gbStream != null) { | |
| 411 | -// eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); | |
| 412 | - } | |
| 413 | - zlmMediaListManager.removeMedia(param.getApp(), param.getStream()); | |
| 414 | - } | |
| 415 | - GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); | |
| 416 | - if (gbStream != null) { | |
| 417 | - if (userSetting.isUsePushingAsStatus()) { | |
| 418 | - eventPublisher.catalogEventPublishForStream(null, gbStream, param.isRegist()?CatalogEvent.ON:CatalogEvent.OFF); | |
| 419 | - } | |
| 420 | - } | |
| 421 | - if (type != null) { | |
| 422 | - // 发送流变化redis消息 | |
| 423 | - JSONObject jsonObject = new JSONObject(); | |
| 424 | - jsonObject.put("serverId", userSetting.getServerId()); | |
| 425 | - jsonObject.put("app", param.getApp()); | |
| 426 | - jsonObject.put("stream", param.getStream()); | |
| 427 | - jsonObject.put("register", param.isRegist()); | |
| 428 | - jsonObject.put("mediaServerId", param.getMediaServerId()); | |
| 429 | - redisCatchStorage.sendStreamChangeMsg(type, jsonObject); | |
| 430 | - } | |
| 431 | - } | |
| 432 | - } | |
| 433 | - if (!param.isRegist()) { | |
| 434 | - List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); | |
| 435 | - if (sendRtpItems.size() > 0) { | |
| 436 | - for (SendRtpItem sendRtpItem : sendRtpItems) { | |
| 437 | - if (sendRtpItem != null && sendRtpItem.getApp().equals(param.getApp())) { | |
| 438 | - String platformId = sendRtpItem.getPlatformId(); | |
| 439 | - ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); | |
| 440 | - Device device = deviceService.getDevice(platformId); | |
| 441 | - | |
| 442 | - try { | |
| 443 | - if (platform != null) { | |
| 444 | - commanderFroPlatform.streamByeCmd(platform, sendRtpItem); | |
| 445 | - redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(), | |
| 446 | - sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | |
| 447 | - } else { | |
| 448 | - cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId()); | |
| 449 | - } | |
| 450 | - } catch (SipException | InvalidArgumentException | ParseException | | |
| 451 | - SsrcTransactionNotFoundException e) { | |
| 452 | - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | |
| 453 | - } | |
| 454 | - } | |
| 455 | - } | |
| 456 | - } | |
| 457 | - } | |
| 458 | - } | |
| 459 | - }); | |
| 460 | - | |
| 461 | - return HookResult.SUCCESS(); | |
| 462 | - } | |
| 463 | - | |
| 464 | - /** | |
| 465 | - * 流无人观看时事件,用户可以通过此事件选择是否关闭无人看的流。 | |
| 466 | - */ | |
| 467 | - @ResponseBody | |
| 468 | - @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") | |
| 469 | - public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) { | |
| 470 | - | |
| 471 | - logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), | |
| 472 | - param.getApp(), param.getStream()); | |
| 473 | - JSONObject ret = new JSONObject(); | |
| 474 | - ret.put("code", 0); | |
| 475 | - // 国标类型的流 | |
| 476 | - if ("rtp".equals(param.getApp())) { | |
| 477 | - ret.put("close", userSetting.getStreamOnDemand()); | |
| 478 | - // 国标流, 点播/录像回放/录像下载 | |
| 479 | - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream()); | |
| 480 | - // 点播 | |
| 481 | - if (inviteInfo != null) { | |
| 482 | - // 录像下载 | |
| 483 | - if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) { | |
| 484 | - ret.put("close", false); | |
| 485 | - return ret; | |
| 486 | - } | |
| 487 | - // 收到无人观看说明流也没有在往上级推送 | |
| 488 | - if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) { | |
| 489 | - List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId( | |
| 490 | - inviteInfo.getChannelId()); | |
| 491 | - if (sendRtpItems.size() > 0) { | |
| 492 | - for (SendRtpItem sendRtpItem : sendRtpItems) { | |
| 493 | - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); | |
| 494 | - try { | |
| 495 | - commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); | |
| 496 | - } catch (SipException | InvalidArgumentException | ParseException e) { | |
| 497 | - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | |
| 498 | - } | |
| 499 | - redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), | |
| 500 | - sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | |
| 501 | - if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) { | |
| 502 | - MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, | |
| 503 | - sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(), | |
| 504 | - sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId()); | |
| 505 | - messageForPushChannel.setPlatFormIndex(parentPlatform.getId()); | |
| 506 | - redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel); | |
| 507 | - } | |
| 508 | - } | |
| 509 | - } | |
| 510 | - } | |
| 511 | - Device device = deviceService.getDevice(inviteInfo.getDeviceId()); | |
| 512 | - if (device != null) { | |
| 513 | - try { | |
| 514 | - // 多查询一次防止已经被处理了 | |
| 515 | - InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(), | |
| 516 | - inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()); | |
| 517 | - if (info != null) { | |
| 518 | - cmder.streamByeCmd(device, inviteInfo.getChannelId(), | |
| 519 | - inviteInfo.getStream(), null); | |
| 520 | - } | |
| 521 | - } catch (InvalidArgumentException | ParseException | SipException | | |
| 522 | - SsrcTransactionNotFoundException e) { | |
| 523 | - logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage()); | |
| 524 | - } | |
| 525 | - } | |
| 526 | - | |
| 527 | - inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), | |
| 528 | - inviteInfo.getChannelId(), inviteInfo.getStream()); | |
| 529 | - storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId()); | |
| 530 | - return ret; | |
| 531 | - } | |
| 532 | - } else { | |
| 533 | - // 非国标流 推流/拉流代理 | |
| 534 | - // 拉流代理 | |
| 535 | - StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); | |
| 536 | - if (streamProxyItem != null) { | |
| 537 | - if (streamProxyItem.isEnableRemoveNoneReader()) { | |
| 538 | - // 无人观看自动移除 | |
| 539 | - ret.put("close", true); | |
| 540 | - streamProxyService.del(param.getApp(), param.getStream()); | |
| 541 | - String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl(); | |
| 542 | - logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url); | |
| 543 | - } else if (streamProxyItem.isEnableDisableNoneReader()) { | |
| 544 | - // 无人观看停用 | |
| 545 | - ret.put("close", true); | |
| 546 | - // 修改数据 | |
| 547 | - streamProxyService.stop(param.getApp(), param.getStream()); | |
| 548 | - } else { | |
| 549 | - // 无人观看不做处理 | |
| 550 | - ret.put("close", false); | |
| 551 | - } | |
| 552 | - return ret; | |
| 553 | - } | |
| 554 | - // TODO 推流具有主动性,暂时不做处理 | |
| 555 | -// StreamPushItem streamPushItem = streamPushService.getPush(app, streamId); | |
| 556 | -// if (streamPushItem != null) { | |
| 557 | -// // TODO 发送停止 | |
| 558 | -// | |
| 559 | -// } | |
| 560 | - } | |
| 561 | - return ret; | |
| 562 | - } | |
| 563 | - | |
| 564 | - /** | |
| 565 | - * 流未找到事件,用户可以在此事件触发时,立即去拉流,这样可以实现按需拉流;此事件对回复不敏感。 | |
| 566 | - */ | |
| 567 | - @ResponseBody | |
| 568 | - @PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8") | |
| 569 | - public DeferredResult<HookResult> onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) { | |
| 570 | - logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | |
| 571 | - | |
| 572 | - DeferredResult<HookResult> defaultResult = new DeferredResult<>(); | |
| 573 | - | |
| 574 | - MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); | |
| 575 | - if (!userSetting.isAutoApplyPlay() || mediaInfo == null) { | |
| 576 | - defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); | |
| 577 | - return defaultResult; | |
| 578 | - } | |
| 579 | - | |
| 580 | - if ("rtp".equals(param.getApp())) { | |
| 581 | - String[] s = param.getStream().split("_"); | |
| 582 | - if ((s.length != 2 && s.length != 4)) { | |
| 583 | - defaultResult.setResult(HookResult.SUCCESS()); | |
| 584 | - return defaultResult; | |
| 585 | - } | |
| 586 | - String deviceId = s[0]; | |
| 587 | - String channelId = s[1]; | |
| 588 | - Device device = redisCatchStorage.getDevice(deviceId); | |
| 589 | - if (device == null) { | |
| 590 | - defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); | |
| 591 | - return defaultResult; | |
| 592 | - } | |
| 593 | - DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); | |
| 594 | - if (deviceChannel == null) { | |
| 595 | - defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); | |
| 596 | - return defaultResult; | |
| 597 | - } | |
| 598 | - if (s.length == 2) { | |
| 599 | - logger.info("[ZLM HOOK] 预览流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | |
| 600 | - | |
| 601 | - RequestMessage msg = new RequestMessage(); | |
| 602 | - String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; | |
| 603 | - boolean exist = resultHolder.exist(key, null); | |
| 604 | - msg.setKey(key); | |
| 605 | - String uuid = UUID.randomUUID().toString(); | |
| 606 | - msg.setId(uuid); | |
| 607 | - DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); | |
| 608 | - | |
| 609 | - result.onTimeout(() -> { | |
| 610 | - logger.info("[ZLM HOOK] 预览流自动点播, 等待超时"); | |
| 611 | - msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); | |
| 612 | - resultHolder.invokeResult(msg); | |
| 613 | - }); | |
| 614 | - | |
| 615 | - resultHolder.put(key, uuid, result); | |
| 616 | - | |
| 617 | - if (!exist) { | |
| 618 | - playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> { | |
| 619 | - msg.setData(new HookResult(code, message)); | |
| 620 | - resultHolder.invokeResult(msg); | |
| 621 | - }); | |
| 622 | - } | |
| 623 | - return result; | |
| 624 | - }else if(s.length == 4){ | |
| 625 | - // 此时为录像回放, 录像回放格式为> 设备ID_通道ID_开始时间_结束时间 | |
| 626 | - String startTimeStr = s[2]; | |
| 627 | - String endTimeStr = s[3]; | |
| 628 | - if (startTimeStr == null || endTimeStr == null || startTimeStr.length() != 14 || endTimeStr.length() != 14) { | |
| 629 | - defaultResult.setResult(HookResult.SUCCESS()); | |
| 630 | - return defaultResult; | |
| 631 | - } | |
| 632 | - String startTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(startTimeStr); | |
| 633 | - String endTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(endTimeStr); | |
| 634 | - logger.info("[ZLM HOOK] 回放流未找到, 发起自动点播:{}->{}->{}/{}-{}-{}", | |
| 635 | - param.getMediaServerId(), param.getSchema(), | |
| 636 | - param.getApp(), param.getStream(), | |
| 637 | - startTime, endTime | |
| 638 | - ); | |
| 639 | - RequestMessage msg = new RequestMessage(); | |
| 640 | - String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId; | |
| 641 | - boolean exist = resultHolder.exist(key, null); | |
| 642 | - msg.setKey(key); | |
| 643 | - String uuid = UUID.randomUUID().toString(); | |
| 644 | - msg.setId(uuid); | |
| 645 | - DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); | |
| 646 | - | |
| 647 | - result.onTimeout(() -> { | |
| 648 | - logger.info("[ZLM HOOK] 回放流自动点播, 等待超时"); | |
| 649 | - // 释放rtpserver | |
| 650 | - msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); | |
| 651 | - resultHolder.invokeResult(msg); | |
| 652 | - }); | |
| 653 | - | |
| 654 | - resultHolder.put(key, uuid, result); | |
| 655 | - | |
| 656 | - if (!exist) { | |
| 657 | - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaInfo, param.getStream(), null, | |
| 658 | - device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); | |
| 659 | - playService.playBack(mediaInfo, ssrcInfo, deviceId, channelId, startTime, endTime, (code, message, data) -> { | |
| 660 | - msg.setData(new HookResult(code, message)); | |
| 661 | - resultHolder.invokeResult(msg); | |
| 662 | - }); | |
| 663 | - } | |
| 664 | - return result; | |
| 665 | - }else { | |
| 666 | - defaultResult.setResult(HookResult.SUCCESS()); | |
| 667 | - return defaultResult; | |
| 668 | - } | |
| 669 | - | |
| 670 | - } else { | |
| 671 | - // 拉流代理 | |
| 672 | - StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); | |
| 673 | - if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) { | |
| 674 | - streamProxyService.start(param.getApp(), param.getStream()); | |
| 675 | - } | |
| 676 | - DeferredResult<HookResult> result = new DeferredResult<>(); | |
| 677 | - result.setResult(HookResult.SUCCESS()); | |
| 678 | - return result; | |
| 679 | - } | |
| 680 | - } | |
| 681 | - | |
| 682 | - /** | |
| 683 | - * 服务器启动事件,可以用于监听服务器崩溃重启;此事件对回复不敏感。 | |
| 684 | - */ | |
| 685 | - @ResponseBody | |
| 686 | - @PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8") | |
| 687 | - public HookResult onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject) { | |
| 688 | - | |
| 689 | - jsonObject.put("ip", request.getRemoteAddr()); | |
| 690 | - ZLMServerConfig zlmServerConfig = JSON.to(ZLMServerConfig.class, jsonObject); | |
| 691 | - zlmServerConfig.setIp(request.getRemoteAddr()); | |
| 692 | - logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId()); | |
| 693 | - taskExecutor.execute(() -> { | |
| 694 | - List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started); | |
| 695 | - if (subscribes != null && subscribes.size() > 0) { | |
| 696 | - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | |
| 697 | - subscribe.response(null, zlmServerConfig); | |
| 698 | - } | |
| 699 | - } | |
| 700 | - mediaServerService.zlmServerOnline(zlmServerConfig); | |
| 701 | - }); | |
| 702 | - | |
| 703 | - return HookResult.SUCCESS(); | |
| 704 | - } | |
| 705 | - | |
| 706 | - /** | |
| 707 | - * 发送rtp(startSendRtp)被动关闭时回调 | |
| 708 | - */ | |
| 709 | - @ResponseBody | |
| 710 | - @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8") | |
| 711 | - public HookResult onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param) { | |
| 712 | - | |
| 713 | - logger.info("[ZLM HOOK] rtp发送关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream()); | |
| 714 | - | |
| 715 | - // 查找对应的上级推流,发送停止 | |
| 716 | - if (!"rtp".equals(param.getApp())) { | |
| 717 | - return HookResult.SUCCESS(); | |
| 718 | - } | |
| 719 | - taskExecutor.execute(() -> { | |
| 720 | - List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); | |
| 721 | - if (sendRtpItems.size() > 0) { | |
| 722 | - for (SendRtpItem sendRtpItem : sendRtpItems) { | |
| 723 | - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); | |
| 724 | - ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc()); | |
| 725 | - try { | |
| 726 | - commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); | |
| 727 | - } catch (SipException | InvalidArgumentException | ParseException e) { | |
| 728 | - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | |
| 729 | - } | |
| 730 | - redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), | |
| 731 | - sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | |
| 732 | - } | |
| 733 | - } | |
| 734 | - }); | |
| 735 | - | |
| 736 | - return HookResult.SUCCESS(); | |
| 737 | - } | |
| 738 | - | |
| 739 | - /** | |
| 740 | - * rtpServer收流超时 | |
| 741 | - */ | |
| 742 | - @ResponseBody | |
| 743 | - @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8") | |
| 744 | - public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam param) { | |
| 745 | - logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc()); | |
| 746 | - | |
| 747 | - taskExecutor.execute(() -> { | |
| 748 | - JSONObject json = (JSONObject) JSON.toJSON(param); | |
| 749 | - List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); | |
| 750 | - if (subscribes != null && subscribes.size() > 0) { | |
| 751 | - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | |
| 752 | - subscribe.response(null, param); | |
| 753 | - } | |
| 754 | - } | |
| 755 | - }); | |
| 756 | - | |
| 757 | - return HookResult.SUCCESS(); | |
| 758 | - } | |
| 759 | - | |
| 760 | - private Map<String, String> urlParamToMap(String params) { | |
| 761 | - HashMap<String, String> map = new HashMap<>(); | |
| 762 | - if (ObjectUtils.isEmpty(params)) { | |
| 763 | - return map; | |
| 764 | - } | |
| 765 | - String[] paramsArray = params.split("&"); | |
| 766 | - if (paramsArray.length == 0) { | |
| 767 | - return map; | |
| 768 | - } | |
| 769 | - for (String param : paramsArray) { | |
| 770 | - String[] paramArray = param.split("="); | |
| 771 | - if (paramArray.length == 2) { | |
| 772 | - map.put(paramArray[0], paramArray[1]); | |
| 773 | - } | |
| 774 | - } | |
| 775 | - return map; | |
| 776 | - } | |
| 777 | -} | |
| 1 | +package com.genersoft.iot.vmp.media.zlm; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson2.JSON; | |
| 4 | +import com.alibaba.fastjson2.JSONObject; | |
| 5 | +import com.genersoft.iot.vmp.common.InviteInfo; | |
| 6 | +import com.genersoft.iot.vmp.common.InviteSessionType; | |
| 7 | +import com.genersoft.iot.vmp.common.StreamInfo; | |
| 8 | +import com.genersoft.iot.vmp.common.VideoManagerConstants; | |
| 9 | +import com.genersoft.iot.vmp.conf.UserSetting; | |
| 10 | +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | |
| 11 | +import com.genersoft.iot.vmp.gb28181.bean.*; | |
| 12 | +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | |
| 13 | +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | |
| 14 | +import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; | |
| 15 | +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 16 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | |
| 17 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | |
| 18 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | |
| 19 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; | |
| 20 | +import com.genersoft.iot.vmp.media.zlm.dto.HookType; | |
| 21 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 22 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; | |
| 23 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; | |
| 24 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.*; | |
| 25 | +import com.genersoft.iot.vmp.service.*; | |
| 26 | +import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; | |
| 27 | +import com.genersoft.iot.vmp.service.bean.SSRCInfo; | |
| 28 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 29 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | |
| 30 | +import com.genersoft.iot.vmp.utils.DateUtil; | |
| 31 | +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | |
| 32 | +import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo; | |
| 33 | +import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo; | |
| 34 | +import com.genersoft.iot.vmp.vmanager.bean.StreamContent; | |
| 35 | +import org.slf4j.Logger; | |
| 36 | +import org.slf4j.LoggerFactory; | |
| 37 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 38 | +import org.springframework.beans.factory.annotation.Qualifier; | |
| 39 | +import org.springframework.data.redis.core.RedisTemplate; | |
| 40 | +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | |
| 41 | +import org.springframework.util.ObjectUtils; | |
| 42 | +import org.springframework.web.bind.annotation.*; | |
| 43 | +import org.springframework.web.context.request.async.DeferredResult; | |
| 44 | + | |
| 45 | +import javax.servlet.http.HttpServletRequest; | |
| 46 | +import javax.sip.InvalidArgumentException; | |
| 47 | +import javax.sip.SipException; | |
| 48 | +import java.text.ParseException; | |
| 49 | +import java.util.HashMap; | |
| 50 | +import java.util.List; | |
| 51 | +import java.util.Map; | |
| 52 | +import java.util.UUID; | |
| 53 | + | |
| 54 | +/** | |
| 55 | + * @description:针对 ZLMediaServer的hook事件监听 | |
| 56 | + * @author: swwheihei | |
| 57 | + * @date: 2020年5月8日 上午10:46:48 | |
| 58 | + */ | |
| 59 | +@RestController | |
| 60 | +@RequestMapping("/index/hook") | |
| 61 | +public class ZLMHttpHookListener { | |
| 62 | + | |
| 63 | + private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class); | |
| 64 | + | |
| 65 | + @Autowired | |
| 66 | + private SIPCommander cmder; | |
| 67 | + | |
| 68 | + @Autowired | |
| 69 | + private SIPCommanderFroPlatform commanderFroPlatform; | |
| 70 | + | |
| 71 | + @Autowired | |
| 72 | + private IPlayService playService; | |
| 73 | + | |
| 74 | + @Autowired | |
| 75 | + private IVideoManagerStorage storager; | |
| 76 | + | |
| 77 | + @Autowired | |
| 78 | + private IRedisCatchStorage redisCatchStorage; | |
| 79 | + | |
| 80 | + @Autowired | |
| 81 | + private IInviteStreamService inviteStreamService; | |
| 82 | + | |
| 83 | + @Autowired | |
| 84 | + private IDeviceService deviceService; | |
| 85 | + | |
| 86 | + @Autowired | |
| 87 | + private IMediaServerService mediaServerService; | |
| 88 | + | |
| 89 | + @Autowired | |
| 90 | + private IStreamProxyService streamProxyService; | |
| 91 | + | |
| 92 | + @Autowired | |
| 93 | + private DeferredResultHolder resultHolder; | |
| 94 | + | |
| 95 | + @Autowired | |
| 96 | + private IMediaService mediaService; | |
| 97 | + | |
| 98 | + @Autowired | |
| 99 | + private EventPublisher eventPublisher; | |
| 100 | + | |
| 101 | + @Autowired | |
| 102 | + private ZLMMediaListManager zlmMediaListManager; | |
| 103 | + | |
| 104 | + @Autowired | |
| 105 | + private ZlmHttpHookSubscribe subscribe; | |
| 106 | + | |
| 107 | + @Autowired | |
| 108 | + private UserSetting userSetting; | |
| 109 | + | |
| 110 | + @Autowired | |
| 111 | + private IUserService userService; | |
| 112 | + | |
| 113 | + @Autowired | |
| 114 | + private VideoStreamSessionManager sessionManager; | |
| 115 | + | |
| 116 | + @Autowired | |
| 117 | + private AssistRESTfulUtils assistRESTfulUtils; | |
| 118 | + | |
| 119 | + @Autowired | |
| 120 | + private SSRCFactory ssrcFactory; | |
| 121 | + | |
| 122 | + @Qualifier("taskExecutor") | |
| 123 | + @Autowired | |
| 124 | + private ThreadPoolTaskExecutor taskExecutor; | |
| 125 | + | |
| 126 | + @Autowired | |
| 127 | + private RedisTemplate<Object, Object> redisTemplate; | |
| 128 | + | |
| 129 | + /** | |
| 130 | + * 服务器定时上报时间,上报间隔可配置,默认10s上报一次 | |
| 131 | + */ | |
| 132 | + @ResponseBody | |
| 133 | + | |
| 134 | + @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8") | |
| 135 | + public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) { | |
| 136 | + | |
| 137 | + | |
| 138 | + taskExecutor.execute(() -> { | |
| 139 | + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive); | |
| 140 | + if (subscribes != null && subscribes.size() > 0) { | |
| 141 | + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | |
| 142 | + subscribe.response(null, param); | |
| 143 | + } | |
| 144 | + } | |
| 145 | + }); | |
| 146 | + mediaServerService.updateMediaServerKeepalive(param.getMediaServerId(), param.getData()); | |
| 147 | + | |
| 148 | + return HookResult.SUCCESS(); | |
| 149 | + } | |
| 150 | + | |
| 151 | + /** | |
| 152 | + * 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。 | |
| 153 | + */ | |
| 154 | + @ResponseBody | |
| 155 | + | |
| 156 | + @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8") | |
| 157 | + public HookResult onPlay(@RequestBody OnPlayHookParam param) { | |
| 158 | + if (logger.isDebugEnabled()) { | |
| 159 | + logger.debug("[ZLM HOOK] 播放鉴权:{}->{}" + param.getMediaServerId(), param); | |
| 160 | + } | |
| 161 | + String mediaServerId = param.getMediaServerId(); | |
| 162 | + | |
| 163 | + taskExecutor.execute(() -> { | |
| 164 | + JSONObject json = (JSONObject) JSON.toJSON(param); | |
| 165 | + ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json); | |
| 166 | + if (subscribe != null) { | |
| 167 | + MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); | |
| 168 | + if (mediaInfo != null) { | |
| 169 | + subscribe.response(mediaInfo, param); | |
| 170 | + } | |
| 171 | + } | |
| 172 | + }); | |
| 173 | + if (!"rtp".equals(param.getApp())) { | |
| 174 | + Map<String, String> paramMap = urlParamToMap(param.getParams()); | |
| 175 | + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | |
| 176 | + if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) { | |
| 177 | + return new HookResult(401, "Unauthorized"); | |
| 178 | + } | |
| 179 | + } | |
| 180 | + | |
| 181 | + return HookResult.SUCCESS(); | |
| 182 | + } | |
| 183 | + | |
| 184 | + /** | |
| 185 | + * rtsp/rtmp/rtp推流鉴权事件。 | |
| 186 | + */ | |
| 187 | + @ResponseBody | |
| 188 | + @PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8") | |
| 189 | + public HookResultForOnPublish onPublish(@RequestBody OnPublishHookParam param) { | |
| 190 | + | |
| 191 | + JSONObject json = (JSONObject) JSON.toJSON(param); | |
| 192 | + | |
| 193 | + logger.info("[ZLM HOOK]推流鉴权:{}->{}", param.getMediaServerId(), param); | |
| 194 | + | |
| 195 | + String mediaServerId = json.getString("mediaServerId"); | |
| 196 | + MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); | |
| 197 | + if (mediaInfo == null) { | |
| 198 | + return new HookResultForOnPublish(200, "success"); | |
| 199 | + } | |
| 200 | + // 推流鉴权的处理 | |
| 201 | + if (!"rtp".equals(param.getApp())) { | |
| 202 | + if (userSetting.getPushAuthority()) { | |
| 203 | + // 推流鉴权 | |
| 204 | + if (param.getParams() == null) { | |
| 205 | + logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)"); | |
| 206 | + return new HookResultForOnPublish(401, "Unauthorized"); | |
| 207 | + } | |
| 208 | + Map<String, String> paramMap = urlParamToMap(param.getParams()); | |
| 209 | + String sign = paramMap.get("sign"); | |
| 210 | + if (sign == null) { | |
| 211 | + logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)"); | |
| 212 | + return new HookResultForOnPublish(401, "Unauthorized"); | |
| 213 | + } | |
| 214 | + // 推流自定义播放鉴权码 | |
| 215 | + String callId = paramMap.get("callId"); | |
| 216 | + // 鉴权配置 | |
| 217 | + boolean hasAuthority = userService.checkPushAuthority(callId, sign); | |
| 218 | + if (!hasAuthority) { | |
| 219 | + logger.info("推流鉴权失败: sign 无权限: callId={}. sign={}", callId, sign); | |
| 220 | + return new HookResultForOnPublish(401, "Unauthorized"); | |
| 221 | + } | |
| 222 | + StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); | |
| 223 | + streamAuthorityInfo.setCallId(callId); | |
| 224 | + streamAuthorityInfo.setSign(sign); | |
| 225 | + // 鉴权通过 | |
| 226 | + redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); | |
| 227 | + // 通知assist新的callId | |
| 228 | + if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) { | |
| 229 | + taskExecutor.execute(() -> { | |
| 230 | + assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null); | |
| 231 | + }); | |
| 232 | + } | |
| 233 | + } | |
| 234 | + } else { | |
| 235 | + zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId()); | |
| 236 | + } | |
| 237 | + | |
| 238 | + | |
| 239 | + HookResultForOnPublish result = HookResultForOnPublish.SUCCESS(); | |
| 240 | + result.setEnable_audio(true); | |
| 241 | + taskExecutor.execute(() -> { | |
| 242 | + ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json); | |
| 243 | + if (subscribe != null) { | |
| 244 | + if (mediaInfo != null) { | |
| 245 | + subscribe.response(mediaInfo, param); | |
| 246 | + } else { | |
| 247 | + new HookResultForOnPublish(1, "zlm not register"); | |
| 248 | + } | |
| 249 | + } | |
| 250 | + }); | |
| 251 | + | |
| 252 | + // 是否录像 | |
| 253 | + if ("rtp".equals(param.getApp())) { | |
| 254 | + result.setEnable_mp4(userSetting.getRecordSip()); | |
| 255 | + } else { | |
| 256 | + result.setEnable_mp4(userSetting.isRecordPushLive()); | |
| 257 | + } | |
| 258 | + // 替换流地址 | |
| 259 | + if ("rtp".equals(param.getApp()) && !mediaInfo.isRtpEnable()) { | |
| 260 | + String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));; | |
| 261 | + InviteInfo inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc); | |
| 262 | + if (inviteInfo != null) { | |
| 263 | + result.setStream_replace(inviteInfo.getStream()); | |
| 264 | + logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream()); | |
| 265 | + } | |
| 266 | + } | |
| 267 | + List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream()); | |
| 268 | + if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { | |
| 269 | + String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); | |
| 270 | + String channelId = ssrcTransactionForAll.get(0).getChannelId(); | |
| 271 | + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); | |
| 272 | + if (deviceChannel != null) { | |
| 273 | + result.setEnable_audio(deviceChannel.isHasAudio()); | |
| 274 | + } | |
| 275 | + // 如果是录像下载就设置视频间隔十秒 | |
| 276 | + if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) { | |
| 277 | + result.setMp4_max_second(10); | |
| 278 | + result.setEnable_mp4(true); | |
| 279 | + } | |
| 280 | + } | |
| 281 | + if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) { | |
| 282 | + logger.info("推流时发现尚未设置录像路径,从assist服务中读取"); | |
| 283 | + JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null); | |
| 284 | + if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) { | |
| 285 | + JSONObject dataJson = info.getJSONObject("data"); | |
| 286 | + if (dataJson != null) { | |
| 287 | + String recordPath = dataJson.getString("record"); | |
| 288 | + userSetting.setRecordPath(recordPath); | |
| 289 | + result.setMp4_save_path(recordPath); | |
| 290 | + // 修改zlm中的录像路径 | |
| 291 | + if (mediaInfo.isAutoConfig()) { | |
| 292 | + taskExecutor.execute(() -> { | |
| 293 | + mediaServerService.setZLMConfig(mediaInfo, false); | |
| 294 | + }); | |
| 295 | + } | |
| 296 | + } | |
| 297 | + } | |
| 298 | + } | |
| 299 | + if (param.getApp().equalsIgnoreCase("rtp")) { | |
| 300 | + String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + param.getStream(); | |
| 301 | + OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(receiveKey); | |
| 302 | + | |
| 303 | + String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + param.getStream(); | |
| 304 | + OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo)redisTemplate.opsForValue().get(receiveKeyForPS); | |
| 305 | + if (otherRtpSendInfo != null || otherPsSendInfo != null) { | |
| 306 | + result.setEnable_mp4(true); | |
| 307 | + } | |
| 308 | + } | |
| 309 | + logger.info("[ZLM HOOK]推流鉴权 响应:{}->{}->>>>{}", param.getMediaServerId(), param, result); | |
| 310 | + return result; | |
| 311 | + } | |
| 312 | + | |
| 313 | + | |
| 314 | + /** | |
| 315 | + * rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。 | |
| 316 | + */ | |
| 317 | + @ResponseBody | |
| 318 | + @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") | |
| 319 | + public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) { | |
| 320 | + | |
| 321 | + if (param.isRegist()) { | |
| 322 | + logger.info("[ZLM HOOK] 流注册, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | |
| 323 | + } else { | |
| 324 | + logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | |
| 325 | + } | |
| 326 | + | |
| 327 | + | |
| 328 | + JSONObject json = (JSONObject) JSON.toJSON(param); | |
| 329 | + taskExecutor.execute(() -> { | |
| 330 | + ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json); | |
| 331 | + MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); | |
| 332 | + if (mediaInfo == null) { | |
| 333 | + logger.info("[ZLM HOOK] 流变化未找到ZLM, {}", param.getMediaServerId()); | |
| 334 | + return; | |
| 335 | + } | |
| 336 | + if (subscribe != null) { | |
| 337 | + subscribe.response(mediaInfo, param); | |
| 338 | + } | |
| 339 | + | |
| 340 | + List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks(); | |
| 341 | + // TODO 重构此处逻辑 | |
| 342 | + boolean isPush = false; | |
| 343 | + if (param.isRegist()) { | |
| 344 | + // 处理流注册的鉴权信息 | |
| 345 | + if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | |
| 346 | + || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | |
| 347 | + || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | |
| 348 | + isPush = true; | |
| 349 | + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | |
| 350 | + if (streamAuthorityInfo == null) { | |
| 351 | + streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); | |
| 352 | + } else { | |
| 353 | + streamAuthorityInfo.setOriginType(param.getOriginType()); | |
| 354 | + streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr()); | |
| 355 | + } | |
| 356 | + redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); | |
| 357 | + } | |
| 358 | + } else { | |
| 359 | + redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream()); | |
| 360 | + } | |
| 361 | + | |
| 362 | + if ("rtsp".equals(param.getSchema())) { | |
| 363 | + // 更新流媒体负载信息 | |
| 364 | + if (param.isRegist()) { | |
| 365 | + mediaServerService.addCount(param.getMediaServerId()); | |
| 366 | + } else { | |
| 367 | + mediaServerService.removeCount(param.getMediaServerId()); | |
| 368 | + } | |
| 369 | + // 设置拉流代理上线/离线 | |
| 370 | + int updateStatusResult = streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream()); | |
| 371 | + if (updateStatusResult > 0) { | |
| 372 | + | |
| 373 | + } | |
| 374 | + | |
| 375 | + if ("rtp".equals(param.getApp()) && !param.isRegist()) { | |
| 376 | + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream()); | |
| 377 | + if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) { | |
| 378 | + inviteStreamService.removeInviteInfo(inviteInfo); | |
| 379 | + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId()); | |
| 380 | + } | |
| 381 | + } else { | |
| 382 | + if (!"rtp".equals(param.getApp())) { | |
| 383 | + String type = OriginType.values()[param.getOriginType()].getType(); | |
| 384 | + if (param.isRegist()) { | |
| 385 | + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo( | |
| 386 | + param.getApp(), param.getStream()); | |
| 387 | + String callId = null; | |
| 388 | + if (streamAuthorityInfo != null) { | |
| 389 | + callId = streamAuthorityInfo.getCallId(); | |
| 390 | + } | |
| 391 | + StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo, | |
| 392 | + param.getApp(), param.getStream(), tracks, callId); | |
| 393 | + param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); | |
| 394 | + redisCatchStorage.addStream(mediaInfo, type, param.getApp(), param.getStream(), param); | |
| 395 | + if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | |
| 396 | + || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | |
| 397 | + || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | |
| 398 | + param.setSeverId(userSetting.getServerId()); | |
| 399 | + zlmMediaListManager.addPush(param); | |
| 400 | + } | |
| 401 | + } else { | |
| 402 | + // 兼容流注销时类型从redis记录获取 | |
| 403 | + OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo( | |
| 404 | + param.getApp(), param.getStream(), param.getMediaServerId()); | |
| 405 | + if (onStreamChangedHookParam != null) { | |
| 406 | + type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType(); | |
| 407 | + redisCatchStorage.removeStream(mediaInfo.getId(), type, param.getApp(), param.getStream()); | |
| 408 | + } | |
| 409 | + GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); | |
| 410 | + if (gbStream != null) { | |
| 411 | +// eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); | |
| 412 | + } | |
| 413 | + zlmMediaListManager.removeMedia(param.getApp(), param.getStream()); | |
| 414 | + } | |
| 415 | + GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); | |
| 416 | + if (gbStream != null) { | |
| 417 | + if (userSetting.isUsePushingAsStatus()) { | |
| 418 | + eventPublisher.catalogEventPublishForStream(null, gbStream, param.isRegist()?CatalogEvent.ON:CatalogEvent.OFF); | |
| 419 | + } | |
| 420 | + } | |
| 421 | + if (type != null) { | |
| 422 | + // 发送流变化redis消息 | |
| 423 | + JSONObject jsonObject = new JSONObject(); | |
| 424 | + jsonObject.put("serverId", userSetting.getServerId()); | |
| 425 | + jsonObject.put("app", param.getApp()); | |
| 426 | + jsonObject.put("stream", param.getStream()); | |
| 427 | + jsonObject.put("register", param.isRegist()); | |
| 428 | + jsonObject.put("mediaServerId", param.getMediaServerId()); | |
| 429 | + redisCatchStorage.sendStreamChangeMsg(type, jsonObject); | |
| 430 | + } | |
| 431 | + } | |
| 432 | + } | |
| 433 | + if (!param.isRegist()) { | |
| 434 | + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); | |
| 435 | + if (sendRtpItems.size() > 0) { | |
| 436 | + for (SendRtpItem sendRtpItem : sendRtpItems) { | |
| 437 | + if (sendRtpItem != null && sendRtpItem.getApp().equals(param.getApp())) { | |
| 438 | + String platformId = sendRtpItem.getPlatformId(); | |
| 439 | + ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); | |
| 440 | + Device device = deviceService.getDevice(platformId); | |
| 441 | + | |
| 442 | + try { | |
| 443 | + if (platform != null) { | |
| 444 | + commanderFroPlatform.streamByeCmd(platform, sendRtpItem); | |
| 445 | + redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(), | |
| 446 | + sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | |
| 447 | + } else { | |
| 448 | + cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId()); | |
| 449 | + } | |
| 450 | + } catch (SipException | InvalidArgumentException | ParseException | | |
| 451 | + SsrcTransactionNotFoundException e) { | |
| 452 | + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | |
| 453 | + } | |
| 454 | + } | |
| 455 | + } | |
| 456 | + } | |
| 457 | + } | |
| 458 | + } | |
| 459 | + }); | |
| 460 | + | |
| 461 | + return HookResult.SUCCESS(); | |
| 462 | + } | |
| 463 | + | |
| 464 | + /** | |
| 465 | + * 流无人观看时事件,用户可以通过此事件选择是否关闭无人看的流。 | |
| 466 | + */ | |
| 467 | + @ResponseBody | |
| 468 | + @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") | |
| 469 | + public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) { | |
| 470 | + | |
| 471 | + logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), | |
| 472 | + param.getApp(), param.getStream()); | |
| 473 | + JSONObject ret = new JSONObject(); | |
| 474 | + ret.put("code", 0); | |
| 475 | + // 国标类型的流 | |
| 476 | + if ("rtp".equals(param.getApp())) { | |
| 477 | + ret.put("close", userSetting.getStreamOnDemand()); | |
| 478 | + // 国标流, 点播/录像回放/录像下载 | |
| 479 | + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream()); | |
| 480 | + // 点播 | |
| 481 | + if (inviteInfo != null) { | |
| 482 | + // 录像下载 | |
| 483 | + if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) { | |
| 484 | + ret.put("close", false); | |
| 485 | + return ret; | |
| 486 | + } | |
| 487 | + // 收到无人观看说明流也没有在往上级推送 | |
| 488 | + if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) { | |
| 489 | + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId( | |
| 490 | + inviteInfo.getChannelId()); | |
| 491 | + if (sendRtpItems.size() > 0) { | |
| 492 | + for (SendRtpItem sendRtpItem : sendRtpItems) { | |
| 493 | + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); | |
| 494 | + try { | |
| 495 | + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); | |
| 496 | + } catch (SipException | InvalidArgumentException | ParseException e) { | |
| 497 | + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | |
| 498 | + } | |
| 499 | + redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), | |
| 500 | + sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | |
| 501 | + if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) { | |
| 502 | + MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, | |
| 503 | + sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(), | |
| 504 | + sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId()); | |
| 505 | + messageForPushChannel.setPlatFormIndex(parentPlatform.getId()); | |
| 506 | + redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel); | |
| 507 | + } | |
| 508 | + } | |
| 509 | + } | |
| 510 | + } | |
| 511 | + Device device = deviceService.getDevice(inviteInfo.getDeviceId()); | |
| 512 | + if (device != null) { | |
| 513 | + try { | |
| 514 | + // 多查询一次防止已经被处理了 | |
| 515 | + InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(), | |
| 516 | + inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()); | |
| 517 | + if (info != null) { | |
| 518 | + cmder.streamByeCmd(device, inviteInfo.getChannelId(), | |
| 519 | + inviteInfo.getStream(), null); | |
| 520 | + } | |
| 521 | + } catch (InvalidArgumentException | ParseException | SipException | | |
| 522 | + SsrcTransactionNotFoundException e) { | |
| 523 | + logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage()); | |
| 524 | + } | |
| 525 | + } | |
| 526 | + | |
| 527 | + inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), | |
| 528 | + inviteInfo.getChannelId(), inviteInfo.getStream()); | |
| 529 | + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId()); | |
| 530 | + return ret; | |
| 531 | + } | |
| 532 | + } else { | |
| 533 | + // 非国标流 推流/拉流代理 | |
| 534 | + // 拉流代理 | |
| 535 | + StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); | |
| 536 | + if (streamProxyItem != null) { | |
| 537 | + if (streamProxyItem.isEnableRemoveNoneReader()) { | |
| 538 | + // 无人观看自动移除 | |
| 539 | + ret.put("close", true); | |
| 540 | + streamProxyService.del(param.getApp(), param.getStream()); | |
| 541 | + String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl(); | |
| 542 | + logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url); | |
| 543 | + } else if (streamProxyItem.isEnableDisableNoneReader()) { | |
| 544 | + // 无人观看停用 | |
| 545 | + ret.put("close", true); | |
| 546 | + // 修改数据 | |
| 547 | + streamProxyService.stop(param.getApp(), param.getStream()); | |
| 548 | + } else { | |
| 549 | + // 无人观看不做处理 | |
| 550 | + ret.put("close", false); | |
| 551 | + } | |
| 552 | + return ret; | |
| 553 | + } | |
| 554 | + // TODO 推流具有主动性,暂时不做处理 | |
| 555 | +// StreamPushItem streamPushItem = streamPushService.getPush(app, streamId); | |
| 556 | +// if (streamPushItem != null) { | |
| 557 | +// // TODO 发送停止 | |
| 558 | +// | |
| 559 | +// } | |
| 560 | + } | |
| 561 | + return ret; | |
| 562 | + } | |
| 563 | + | |
| 564 | + /** | |
| 565 | + * 流未找到事件,用户可以在此事件触发时,立即去拉流,这样可以实现按需拉流;此事件对回复不敏感。 | |
| 566 | + */ | |
| 567 | + @ResponseBody | |
| 568 | + @PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8") | |
| 569 | + public DeferredResult<HookResult> onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) { | |
| 570 | + logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | |
| 571 | + | |
| 572 | + DeferredResult<HookResult> defaultResult = new DeferredResult<>(); | |
| 573 | + | |
| 574 | + MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); | |
| 575 | + if (!userSetting.isAutoApplyPlay() || mediaInfo == null) { | |
| 576 | + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); | |
| 577 | + return defaultResult; | |
| 578 | + } | |
| 579 | + | |
| 580 | + if ("rtp".equals(param.getApp())) { | |
| 581 | + String[] s = param.getStream().split("_"); | |
| 582 | + if ((s.length != 2 && s.length != 4)) { | |
| 583 | + defaultResult.setResult(HookResult.SUCCESS()); | |
| 584 | + return defaultResult; | |
| 585 | + } | |
| 586 | + String deviceId = s[0]; | |
| 587 | + String channelId = s[1]; | |
| 588 | + Device device = redisCatchStorage.getDevice(deviceId); | |
| 589 | + if (device == null) { | |
| 590 | + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); | |
| 591 | + return defaultResult; | |
| 592 | + } | |
| 593 | + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); | |
| 594 | + if (deviceChannel == null) { | |
| 595 | + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); | |
| 596 | + return defaultResult; | |
| 597 | + } | |
| 598 | + if (s.length == 2) { | |
| 599 | + logger.info("[ZLM HOOK] 预览流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | |
| 600 | + | |
| 601 | + RequestMessage msg = new RequestMessage(); | |
| 602 | + String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; | |
| 603 | + boolean exist = resultHolder.exist(key, null); | |
| 604 | + msg.setKey(key); | |
| 605 | + String uuid = UUID.randomUUID().toString(); | |
| 606 | + msg.setId(uuid); | |
| 607 | + DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); | |
| 608 | + | |
| 609 | + result.onTimeout(() -> { | |
| 610 | + logger.info("[ZLM HOOK] 预览流自动点播, 等待超时"); | |
| 611 | + msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); | |
| 612 | + resultHolder.invokeResult(msg); | |
| 613 | + }); | |
| 614 | + | |
| 615 | + resultHolder.put(key, uuid, result); | |
| 616 | + | |
| 617 | + if (!exist) { | |
| 618 | + playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> { | |
| 619 | + msg.setData(new HookResult(code, message)); | |
| 620 | + resultHolder.invokeResult(msg); | |
| 621 | + }); | |
| 622 | + } | |
| 623 | + return result; | |
| 624 | + }else if(s.length == 4){ | |
| 625 | + // 此时为录像回放, 录像回放格式为> 设备ID_通道ID_开始时间_结束时间 | |
| 626 | + String startTimeStr = s[2]; | |
| 627 | + String endTimeStr = s[3]; | |
| 628 | + if (startTimeStr == null || endTimeStr == null || startTimeStr.length() != 14 || endTimeStr.length() != 14) { | |
| 629 | + defaultResult.setResult(HookResult.SUCCESS()); | |
| 630 | + return defaultResult; | |
| 631 | + } | |
| 632 | + String startTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(startTimeStr); | |
| 633 | + String endTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(endTimeStr); | |
| 634 | + logger.info("[ZLM HOOK] 回放流未找到, 发起自动点播:{}->{}->{}/{}-{}-{}", | |
| 635 | + param.getMediaServerId(), param.getSchema(), | |
| 636 | + param.getApp(), param.getStream(), | |
| 637 | + startTime, endTime | |
| 638 | + ); | |
| 639 | + RequestMessage msg = new RequestMessage(); | |
| 640 | + String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId; | |
| 641 | + boolean exist = resultHolder.exist(key, null); | |
| 642 | + msg.setKey(key); | |
| 643 | + String uuid = UUID.randomUUID().toString(); | |
| 644 | + msg.setId(uuid); | |
| 645 | + DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); | |
| 646 | + | |
| 647 | + result.onTimeout(() -> { | |
| 648 | + logger.info("[ZLM HOOK] 回放流自动点播, 等待超时"); | |
| 649 | + // 释放rtpserver | |
| 650 | + msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); | |
| 651 | + resultHolder.invokeResult(msg); | |
| 652 | + }); | |
| 653 | + | |
| 654 | + resultHolder.put(key, uuid, result); | |
| 655 | + | |
| 656 | + if (!exist) { | |
| 657 | + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaInfo, param.getStream(), null, | |
| 658 | + device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); | |
| 659 | + playService.playBack(mediaInfo, ssrcInfo, deviceId, channelId, startTime, endTime, (code, message, data) -> { | |
| 660 | + msg.setData(new HookResult(code, message)); | |
| 661 | + resultHolder.invokeResult(msg); | |
| 662 | + }); | |
| 663 | + } | |
| 664 | + return result; | |
| 665 | + }else { | |
| 666 | + defaultResult.setResult(HookResult.SUCCESS()); | |
| 667 | + return defaultResult; | |
| 668 | + } | |
| 669 | + | |
| 670 | + } else { | |
| 671 | + // 拉流代理 | |
| 672 | + StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); | |
| 673 | + if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) { | |
| 674 | + streamProxyService.start(param.getApp(), param.getStream()); | |
| 675 | + } | |
| 676 | + DeferredResult<HookResult> result = new DeferredResult<>(); | |
| 677 | + result.setResult(HookResult.SUCCESS()); | |
| 678 | + return result; | |
| 679 | + } | |
| 680 | + } | |
| 681 | + | |
| 682 | + /** | |
| 683 | + * 服务器启动事件,可以用于监听服务器崩溃重启;此事件对回复不敏感。 | |
| 684 | + */ | |
| 685 | + @ResponseBody | |
| 686 | + @PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8") | |
| 687 | + public HookResult onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject) { | |
| 688 | + | |
| 689 | + jsonObject.put("ip", request.getRemoteAddr()); | |
| 690 | + ZLMServerConfig zlmServerConfig = JSON.to(ZLMServerConfig.class, jsonObject); | |
| 691 | + zlmServerConfig.setIp(request.getRemoteAddr()); | |
| 692 | + logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId()); | |
| 693 | + taskExecutor.execute(() -> { | |
| 694 | + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started); | |
| 695 | + if (subscribes != null && subscribes.size() > 0) { | |
| 696 | + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | |
| 697 | + subscribe.response(null, zlmServerConfig); | |
| 698 | + } | |
| 699 | + } | |
| 700 | + mediaServerService.zlmServerOnline(zlmServerConfig); | |
| 701 | + }); | |
| 702 | + | |
| 703 | + return HookResult.SUCCESS(); | |
| 704 | + } | |
| 705 | + | |
| 706 | + /** | |
| 707 | + * 发送rtp(startSendRtp)被动关闭时回调 | |
| 708 | + */ | |
| 709 | + @ResponseBody | |
| 710 | + @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8") | |
| 711 | + public HookResult onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param) { | |
| 712 | + | |
| 713 | + logger.info("[ZLM HOOK] rtp发送关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream()); | |
| 714 | + | |
| 715 | + // 查找对应的上级推流,发送停止 | |
| 716 | + if (!"rtp".equals(param.getApp())) { | |
| 717 | + return HookResult.SUCCESS(); | |
| 718 | + } | |
| 719 | + taskExecutor.execute(() -> { | |
| 720 | + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); | |
| 721 | + if (sendRtpItems.size() > 0) { | |
| 722 | + for (SendRtpItem sendRtpItem : sendRtpItems) { | |
| 723 | + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); | |
| 724 | + ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc()); | |
| 725 | + try { | |
| 726 | + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); | |
| 727 | + } catch (SipException | InvalidArgumentException | ParseException e) { | |
| 728 | + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | |
| 729 | + } | |
| 730 | + redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), | |
| 731 | + sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | |
| 732 | + } | |
| 733 | + } | |
| 734 | + }); | |
| 735 | + | |
| 736 | + return HookResult.SUCCESS(); | |
| 737 | + } | |
| 738 | + | |
| 739 | + /** | |
| 740 | + * rtpServer收流超时 | |
| 741 | + */ | |
| 742 | + @ResponseBody | |
| 743 | + @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8") | |
| 744 | + public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam param) { | |
| 745 | + logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc()); | |
| 746 | + | |
| 747 | + taskExecutor.execute(() -> { | |
| 748 | + JSONObject json = (JSONObject) JSON.toJSON(param); | |
| 749 | + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); | |
| 750 | + if (subscribes != null && subscribes.size() > 0) { | |
| 751 | + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | |
| 752 | + subscribe.response(null, param); | |
| 753 | + } | |
| 754 | + } | |
| 755 | + }); | |
| 756 | + | |
| 757 | + return HookResult.SUCCESS(); | |
| 758 | + } | |
| 759 | + | |
| 760 | + private Map<String, String> urlParamToMap(String params) { | |
| 761 | + HashMap<String, String> map = new HashMap<>(); | |
| 762 | + if (ObjectUtils.isEmpty(params)) { | |
| 763 | + return map; | |
| 764 | + } | |
| 765 | + String[] paramsArray = params.split("&"); | |
| 766 | + if (paramsArray.length == 0) { | |
| 767 | + return map; | |
| 768 | + } | |
| 769 | + for (String param : paramsArray) { | |
| 770 | + String[] paramArray = param.split("="); | |
| 771 | + if (paramArray.length == 2) { | |
| 772 | + map.put(paramArray[0], paramArray[1]); | |
| 773 | + } | |
| 774 | + } | |
| 775 | + return map; | |
| 776 | + } | |
| 777 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java
100644 → 100755
| ... | ... | @@ -42,7 +42,7 @@ public class ZLMServerFactory { |
| 42 | 42 | * @param tcpMode 0/null udp 模式,1 tcp 被动模式, 2 tcp 主动模式。 |
| 43 | 43 | * @return |
| 44 | 44 | */ |
| 45 | - public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port, Boolean reUsePort, Integer tcpMode) { | |
| 45 | + public int createRTPServer(MediaServerItem mediaServerItem, String streamId, long ssrc, Integer port, Boolean reUsePort, Integer tcpMode) { | |
| 46 | 46 | int result = -1; |
| 47 | 47 | // 查询此rtp server 是否已经存在 |
| 48 | 48 | JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ChannelOnlineEvent.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRtpServerTimeout.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForServerStarted.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamChange.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookType.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IHookSubscribe.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ServerKeepaliveData.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamAuthorityInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMRunInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPlayHookParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPublishHookParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRtpServerTimeoutHookParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnSendRtpStoppedHookParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnServerKeepaliveHookParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNoneReaderHookParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNotFoundHookParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OriginType.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMEventAbstract.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOfflineEvent.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOnlineEvent.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IDeviceAlarmService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/ILogService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
100644 → 100755
| ... | ... | @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 6 | 6 | import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData; |
| 7 | 7 | import com.genersoft.iot.vmp.service.bean.MediaServerLoad; |
| 8 | 8 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 9 | +import com.genersoft.iot.vmp.vmanager.bean.RecordFile; | |
| 9 | 10 | |
| 10 | 11 | import java.util.List; |
| 11 | 12 | |
| ... | ... | @@ -93,4 +94,14 @@ public interface IMediaServerService { |
| 93 | 94 | * @return |
| 94 | 95 | */ |
| 95 | 96 | MediaServerLoad getLoad(MediaServerItem mediaServerItem); |
| 97 | + | |
| 98 | + /** | |
| 99 | + * 按时间查找录像文件 | |
| 100 | + */ | |
| 101 | + List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems); | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * 查找存在录像文件的时间 | |
| 105 | + */ | |
| 106 | + List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems); | |
| 96 | 107 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IMediaService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IPlatformChannelService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IRoleService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IUserService.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/ErrorCallback.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/InviteTimeOutCallback.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/MediaServerLoad.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/MessageForPushChannel.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/MessageForPushChannelResponse.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/PushStreamStatusChangeFromRedisDto.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/RequestPushStreamMsg.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/RequestSendItemMsg.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/ResponseSendItemMsg.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/StreamPushItemFromRedis.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/ThirdPartyGB.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/WvpRedisMsg.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/WvpRedisMsgCmd.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
100644 → 100755
| ... | ... | @@ -210,7 +210,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 210 | 210 | redisCatchStorage.updateDevice(device); |
| 211 | 211 | deviceMapper.update(device); |
| 212 | 212 | //进行通道离线 |
| 213 | - deviceChannelMapper.offlineByDeviceId(deviceId); | |
| 213 | +// deviceChannelMapper.offlineByDeviceId(deviceId); | |
| 214 | 214 | // 离线释放所有ssrc |
| 215 | 215 | List<SsrcTransaction> ssrcTransactions = streamSession.getSsrcTransactionForAll(deviceId, null, null, null); |
| 216 | 216 | if (ssrcTransactions != null && ssrcTransactions.size() > 0) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/LogServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
100644 → 100755
| ... | ... | @@ -24,23 +24,30 @@ import com.genersoft.iot.vmp.utils.DateUtil; |
| 24 | 24 | import com.genersoft.iot.vmp.utils.JsonUtil; |
| 25 | 25 | import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
| 26 | 26 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 27 | +import com.genersoft.iot.vmp.vmanager.bean.RecordFile; | |
| 27 | 28 | import okhttp3.OkHttpClient; |
| 28 | 29 | import okhttp3.Request; |
| 29 | 30 | import okhttp3.Response; |
| 30 | 31 | import org.slf4j.Logger; |
| 31 | 32 | import org.slf4j.LoggerFactory; |
| 32 | 33 | import org.springframework.beans.factory.annotation.Autowired; |
| 34 | +import org.springframework.beans.factory.annotation.Qualifier; | |
| 33 | 35 | import org.springframework.beans.factory.annotation.Value; |
| 34 | 36 | import org.springframework.data.redis.core.RedisTemplate; |
| 35 | 37 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; |
| 38 | +import org.springframework.scheduling.annotation.Async; | |
| 39 | +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | |
| 36 | 40 | import org.springframework.stereotype.Service; |
| 37 | 41 | import org.springframework.transaction.TransactionDefinition; |
| 38 | 42 | import org.springframework.transaction.TransactionStatus; |
| 43 | +import org.springframework.util.Assert; | |
| 39 | 44 | import org.springframework.util.ObjectUtils; |
| 40 | 45 | |
| 41 | 46 | import java.io.File; |
| 42 | 47 | import java.time.LocalDateTime; |
| 43 | 48 | import java.util.*; |
| 49 | +import java.util.concurrent.CompletableFuture; | |
| 50 | +import java.util.concurrent.ExecutionException; | |
| 44 | 51 | |
| 45 | 52 | /** |
| 46 | 53 | * 媒体服务器节点管理 |
| ... | ... | @@ -104,6 +111,11 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 104 | 111 | @Autowired |
| 105 | 112 | private RedisTemplate<Object, Object> redisTemplate; |
| 106 | 113 | |
| 114 | + @Qualifier("taskExecutor") | |
| 115 | + @Autowired | |
| 116 | + private ThreadPoolTaskExecutor taskExecutor; | |
| 117 | + | |
| 118 | + | |
| 107 | 119 | |
| 108 | 120 | /** |
| 109 | 121 | * 初始化 |
| ... | ... | @@ -149,7 +161,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 149 | 161 | } |
| 150 | 162 | |
| 151 | 163 | if (streamId == null) { |
| 152 | - streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); | |
| 164 | + streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase(); | |
| 153 | 165 | } |
| 154 | 166 | int ssrcCheckParam = 0; |
| 155 | 167 | if (ssrcCheck && tcpMode > 1) { |
| ... | ... | @@ -158,7 +170,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 158 | 170 | } |
| 159 | 171 | int rtpServerPort; |
| 160 | 172 | if (mediaServerItem.isRtpEnable()) { |
| 161 | - rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0)?Integer.parseInt(ssrc):0, port, reUsePort, tcpMode); | |
| 173 | + rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0) ? Long.parseLong(ssrc) : 0, port, reUsePort, tcpMode); | |
| 162 | 174 | } else { |
| 163 | 175 | rtpServerPort = mediaServerItem.getRtpProxyPort(); |
| 164 | 176 | } |
| ... | ... | @@ -749,4 +761,89 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 749 | 761 | return result; |
| 750 | 762 | } |
| 751 | 763 | |
| 764 | + @Override | |
| 765 | + public List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) { | |
| 766 | + Assert.notNull(app, "app不存在"); | |
| 767 | + Assert.notNull(stream, "stream不存在"); | |
| 768 | + Assert.notNull(startTime, "startTime不存在"); | |
| 769 | + Assert.notNull(endTime, "endTime不存在"); | |
| 770 | + Assert.notEmpty(mediaServerItems, "流媒体列表为空"); | |
| 771 | + | |
| 772 | + CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()]; | |
| 773 | + for (int i = 0; i < mediaServerItems.size(); i++) { | |
| 774 | + completableFutures[i] = getRecordFilesForOne(app, stream, startTime, endTime, mediaServerItems.get(i)); | |
| 775 | + } | |
| 776 | + List<RecordFile> result = new ArrayList<>(); | |
| 777 | + for (int i = 0; i < completableFutures.length; i++) { | |
| 778 | + try { | |
| 779 | + List<RecordFile> list = (List<RecordFile>) completableFutures[i].get(); | |
| 780 | + if (!list.isEmpty()) { | |
| 781 | + for (int g = 0; g < list.size(); g++) { | |
| 782 | + list.get(g).setMediaServerId(mediaServerItems.get(i).getId()); | |
| 783 | + } | |
| 784 | + result.addAll(list); | |
| 785 | + } | |
| 786 | + } catch (InterruptedException e) { | |
| 787 | + throw new RuntimeException(e); | |
| 788 | + } catch (ExecutionException e) { | |
| 789 | + throw new RuntimeException(e); | |
| 790 | + } | |
| 791 | + } | |
| 792 | + Comparator<RecordFile> comparator = Comparator.comparing(RecordFile::getFileName); | |
| 793 | + result.sort(comparator); | |
| 794 | + return result; | |
| 795 | + } | |
| 796 | + | |
| 797 | + @Override | |
| 798 | + public List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) { | |
| 799 | + Assert.notNull(app, "app不存在"); | |
| 800 | + Assert.notNull(stream, "stream不存在"); | |
| 801 | + Assert.notEmpty(mediaServerItems, "流媒体列表为空"); | |
| 802 | + CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()]; | |
| 803 | + | |
| 804 | + for (int i = 0; i < mediaServerItems.size(); i++) { | |
| 805 | + completableFutures[i] = getRecordDatesForOne(app, stream, year, month, mediaServerItems.get(i)); | |
| 806 | + } | |
| 807 | + List<String> result = new ArrayList<>(); | |
| 808 | + CompletableFuture.allOf(completableFutures).join(); | |
| 809 | + for (CompletableFuture completableFuture : completableFutures) { | |
| 810 | + try { | |
| 811 | + List<String> list = (List<String>) completableFuture.get(); | |
| 812 | + result.addAll(list); | |
| 813 | + } catch (InterruptedException e) { | |
| 814 | + throw new RuntimeException(e); | |
| 815 | + } catch (ExecutionException e) { | |
| 816 | + throw new RuntimeException(e); | |
| 817 | + } | |
| 818 | + } | |
| 819 | + Collections.sort(result); | |
| 820 | + return result; | |
| 821 | + } | |
| 822 | + | |
| 823 | + @Async | |
| 824 | + public CompletableFuture<List<String>> getRecordDatesForOne(String app, String stream, int year, int month, MediaServerItem mediaServerItem) { | |
| 825 | + JSONObject fileListJson = assistRESTfulUtils.getDateList(mediaServerItem, app, stream, year, month); | |
| 826 | + if (fileListJson != null && !fileListJson.isEmpty()) { | |
| 827 | + if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) { | |
| 828 | + JSONArray data = fileListJson.getJSONArray("data"); | |
| 829 | + return CompletableFuture.completedFuture(data.toJavaList(String.class)); | |
| 830 | + } | |
| 831 | + } | |
| 832 | + return CompletableFuture.completedFuture(new ArrayList<>()); | |
| 833 | + } | |
| 834 | + | |
| 835 | + @Async | |
| 836 | + public CompletableFuture<List<RecordFile>> getRecordFilesForOne(String app, String stream, String startTime, String endTime, MediaServerItem mediaServerItem) { | |
| 837 | + JSONObject fileListJson = assistRESTfulUtils.getFileList(mediaServerItem, 1, 100000000, app, stream, startTime, endTime); | |
| 838 | + if (fileListJson != null && !fileListJson.isEmpty()) { | |
| 839 | + if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) { | |
| 840 | + JSONObject data = fileListJson.getJSONObject("data"); | |
| 841 | + JSONArray list = data.getJSONArray("list"); | |
| 842 | + if (list != null) { | |
| 843 | + return CompletableFuture.completedFuture(list.toJavaList(RecordFile.class)); | |
| 844 | + } | |
| 845 | + } | |
| 846 | + } | |
| 847 | + return CompletableFuture.completedFuture(new ArrayList<>()); | |
| 848 | + } | |
| 752 | 849 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/RoleServerImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGpsMsgListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamResponseListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusMsgListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisStreamMsgListener.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/ChannelSourceInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/LogDto.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/PlatformRegisterInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/RecordInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/Role.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/User.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/Coordtransform.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
100644 → 100755
| 1 | 1 | package com.genersoft.iot.vmp.utils; |
| 2 | 2 | |
| 3 | 3 | |
| 4 | +import org.apache.commons.lang3.ObjectUtils; | |
| 5 | + | |
| 4 | 6 | import java.time.Instant; |
| 5 | 7 | import java.time.LocalDate; |
| 6 | 8 | import java.time.LocalDateTime; |
| ... | ... | @@ -109,6 +111,9 @@ public class DateUtil { |
| 109 | 111 | } |
| 110 | 112 | |
| 111 | 113 | public static long getDifferenceForNow(String keepaliveTime) { |
| 114 | + if (ObjectUtils.isEmpty(keepaliveTime)) { | |
| 115 | + return 0; | |
| 116 | + } | |
| 112 | 117 | Instant beforeInstant = Instant.from(formatter.parse(keepaliveTime)); |
| 113 | 118 | return ChronoUnit.MILLIS.between(beforeInstant, Instant.now()); |
| 114 | 119 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/utils/GitUtil.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/GpsUtil.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/JsonUtil.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.utils; | |
| 2 | - | |
| 3 | -import org.springframework.beans.BeansException; | |
| 4 | -import org.springframework.context.ApplicationContext; | |
| 5 | -import org.springframework.context.ApplicationContextAware; | |
| 6 | -import org.springframework.stereotype.Component; | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * @description:spring bean获取工厂,获取spring中的已初始化的bean | |
| 10 | - * @author: swwheihei | |
| 11 | - * @date: 2019年6月25日 下午4:51:52 | |
| 12 | - * | |
| 13 | - */ | |
| 14 | -@Component | |
| 15 | -public class SpringBeanFactory implements ApplicationContextAware { | |
| 16 | - | |
| 17 | - // Spring应用上下文环境 | |
| 18 | - private static ApplicationContext applicationContext; | |
| 19 | - | |
| 20 | - /** | |
| 21 | - * 实现ApplicationContextAware接口的回调方法,设置上下文环境 | |
| 22 | - */ | |
| 23 | - @Override | |
| 24 | - public void setApplicationContext(ApplicationContext applicationContext) | |
| 25 | - throws BeansException { | |
| 26 | - SpringBeanFactory.applicationContext = applicationContext; | |
| 27 | - } | |
| 28 | - | |
| 29 | - public static ApplicationContext getApplicationContext() { | |
| 30 | - return applicationContext; | |
| 31 | - } | |
| 32 | - | |
| 33 | - /** | |
| 34 | - * 获取对象 这里重写了bean方法,起主要作用 | |
| 35 | - */ | |
| 36 | - public static <T> T getBean(String beanId) throws BeansException { | |
| 37 | - if (applicationContext == null) { | |
| 38 | - return null; | |
| 39 | - } | |
| 40 | - return (T) applicationContext.getBean(beanId); | |
| 41 | - } | |
| 42 | - | |
| 43 | - /** | |
| 44 | - * 获取当前环境 | |
| 45 | - */ | |
| 46 | - public static String getActiveProfile() { | |
| 47 | - return applicationContext.getEnvironment().getActiveProfiles()[0]; | |
| 48 | - } | |
| 49 | - | |
| 50 | -} | |
| 1 | +package com.genersoft.iot.vmp.utils; | |
| 2 | + | |
| 3 | +import org.springframework.beans.BeansException; | |
| 4 | +import org.springframework.context.ApplicationContext; | |
| 5 | +import org.springframework.context.ApplicationContextAware; | |
| 6 | +import org.springframework.stereotype.Component; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * @description:spring bean获取工厂,获取spring中的已初始化的bean | |
| 10 | + * @author: swwheihei | |
| 11 | + * @date: 2019年6月25日 下午4:51:52 | |
| 12 | + * | |
| 13 | + */ | |
| 14 | +@Component | |
| 15 | +public class SpringBeanFactory implements ApplicationContextAware { | |
| 16 | + | |
| 17 | + // Spring应用上下文环境 | |
| 18 | + private static ApplicationContext applicationContext; | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * 实现ApplicationContextAware接口的回调方法,设置上下文环境 | |
| 22 | + */ | |
| 23 | + @Override | |
| 24 | + public void setApplicationContext(ApplicationContext applicationContext) | |
| 25 | + throws BeansException { | |
| 26 | + SpringBeanFactory.applicationContext = applicationContext; | |
| 27 | + } | |
| 28 | + | |
| 29 | + public static ApplicationContext getApplicationContext() { | |
| 30 | + return applicationContext; | |
| 31 | + } | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 获取对象 这里重写了bean方法,起主要作用 | |
| 35 | + */ | |
| 36 | + public static <T> T getBean(String beanId) throws BeansException { | |
| 37 | + if (applicationContext == null) { | |
| 38 | + return null; | |
| 39 | + } | |
| 40 | + return (T) applicationContext.getBean(beanId); | |
| 41 | + } | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * 获取当前环境 | |
| 45 | + */ | |
| 46 | + public static String getActiveProfile() { | |
| 47 | + return applicationContext.getEnvironment().getActiveProfiles()[0]; | |
| 48 | + } | |
| 49 | + | |
| 50 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/utils/SystemInfoUtils.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/UJson.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.utils.redis; | |
| 2 | - | |
| 3 | -import com.alibaba.fastjson2.JSON; | |
| 4 | -import com.alibaba.fastjson2.JSONReader; | |
| 5 | -import com.alibaba.fastjson2.JSONWriter; | |
| 6 | -import org.springframework.data.redis.serializer.RedisSerializer; | |
| 7 | -import org.springframework.data.redis.serializer.SerializationException; | |
| 8 | - | |
| 9 | -import java.nio.charset.Charset; | |
| 10 | - | |
| 11 | -/** | |
| 12 | - * @description:使用fastjson实现redis的序列化 | |
| 13 | - * @author: swwheihei | |
| 14 | - * @date: 2020年5月6日 下午8:40:11 | |
| 15 | - */ | |
| 16 | -public class FastJsonRedisSerializer<T> implements RedisSerializer<T> { | |
| 17 | - | |
| 18 | - public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); | |
| 19 | - | |
| 20 | - private Class<T> clazz; | |
| 21 | - | |
| 22 | - public FastJsonRedisSerializer(Class<T> clazz) { | |
| 23 | - super(); | |
| 24 | - this.clazz = clazz; | |
| 25 | - } | |
| 26 | - | |
| 27 | - @Override | |
| 28 | - public byte[] serialize(T t) throws SerializationException { | |
| 29 | - if (t == null) { | |
| 30 | - return new byte[0]; | |
| 31 | - } | |
| 32 | - return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName, JSONWriter.Feature.WritePairAsJavaBean).getBytes(DEFAULT_CHARSET); | |
| 33 | - } | |
| 34 | - | |
| 35 | - @Override | |
| 36 | - public T deserialize(byte[] bytes) throws SerializationException { | |
| 37 | - if (bytes == null || bytes.length <= 0) { | |
| 38 | - return null; | |
| 39 | - } | |
| 40 | - String str = new String(bytes, DEFAULT_CHARSET); | |
| 41 | - return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType); | |
| 42 | - } | |
| 43 | - | |
| 44 | - | |
| 45 | -} | |
| 1 | +package com.genersoft.iot.vmp.utils.redis; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson2.JSON; | |
| 4 | +import com.alibaba.fastjson2.JSONReader; | |
| 5 | +import com.alibaba.fastjson2.JSONWriter; | |
| 6 | +import org.springframework.data.redis.serializer.RedisSerializer; | |
| 7 | +import org.springframework.data.redis.serializer.SerializationException; | |
| 8 | + | |
| 9 | +import java.nio.charset.Charset; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * @description:使用fastjson实现redis的序列化 | |
| 13 | + * @author: swwheihei | |
| 14 | + * @date: 2020年5月6日 下午8:40:11 | |
| 15 | + */ | |
| 16 | +public class FastJsonRedisSerializer<T> implements RedisSerializer<T> { | |
| 17 | + | |
| 18 | + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); | |
| 19 | + | |
| 20 | + private Class<T> clazz; | |
| 21 | + | |
| 22 | + public FastJsonRedisSerializer(Class<T> clazz) { | |
| 23 | + super(); | |
| 24 | + this.clazz = clazz; | |
| 25 | + } | |
| 26 | + | |
| 27 | + @Override | |
| 28 | + public byte[] serialize(T t) throws SerializationException { | |
| 29 | + if (t == null) { | |
| 30 | + return new byte[0]; | |
| 31 | + } | |
| 32 | + return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName, JSONWriter.Feature.WritePairAsJavaBean).getBytes(DEFAULT_CHARSET); | |
| 33 | + } | |
| 34 | + | |
| 35 | + @Override | |
| 36 | + public T deserialize(byte[] bytes) throws SerializationException { | |
| 37 | + if (bytes == null || bytes.length <= 0) { | |
| 38 | + return null; | |
| 39 | + } | |
| 40 | + String str = new String(bytes, DEFAULT_CHARSET); | |
| 41 | + return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType); | |
| 42 | + } | |
| 43 | + | |
| 44 | + | |
| 45 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
100644 → 100755
| 1 | -package com.genersoft.iot.vmp.utils.redis; | |
| 2 | - | |
| 3 | -import com.google.common.collect.Lists; | |
| 4 | -import org.springframework.data.redis.core.Cursor; | |
| 5 | -import org.springframework.data.redis.core.RedisCallback; | |
| 6 | -import org.springframework.data.redis.core.RedisTemplate; | |
| 7 | -import org.springframework.data.redis.core.ScanOptions; | |
| 8 | - | |
| 9 | -import java.util.ArrayList; | |
| 10 | -import java.util.HashSet; | |
| 11 | -import java.util.List; | |
| 12 | -import java.util.Set; | |
| 13 | - | |
| 14 | -/** | |
| 15 | - * Redis工具类 | |
| 16 | - * | |
| 17 | - * @author swwheihei | |
| 18 | - * @date 2020年5月6日 下午8:27:29 | |
| 19 | - */ | |
| 20 | -@SuppressWarnings(value = {"rawtypes", "unchecked"}) | |
| 21 | -public class RedisUtil { | |
| 22 | - | |
| 23 | - /** | |
| 24 | - * 模糊查询 | |
| 25 | - * | |
| 26 | - * @param query 查询参数 | |
| 27 | - * @return | |
| 28 | - */ | |
| 29 | - public static List<Object> scan(RedisTemplate redisTemplate, String query) { | |
| 30 | - | |
| 31 | - Set<String> resultKeys = (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> { | |
| 32 | - ScanOptions scanOptions = ScanOptions.scanOptions().match("*" + query + "*").count(1000).build(); | |
| 33 | - Cursor<byte[]> scan = connection.scan(scanOptions); | |
| 34 | - Set<String> keys = new HashSet<>(); | |
| 35 | - while (scan.hasNext()) { | |
| 36 | - byte[] next = scan.next(); | |
| 37 | - keys.add(new String(next)); | |
| 38 | - } | |
| 39 | - return keys; | |
| 40 | - }); | |
| 41 | - | |
| 42 | - return Lists.newArrayList(resultKeys); | |
| 43 | - } | |
| 44 | -} | |
| 45 | - | |
| 46 | - | |
| 47 | - | |
| 1 | +package com.genersoft.iot.vmp.utils.redis; | |
| 2 | + | |
| 3 | +import com.google.common.collect.Lists; | |
| 4 | +import org.springframework.data.redis.core.Cursor; | |
| 5 | +import org.springframework.data.redis.core.RedisCallback; | |
| 6 | +import org.springframework.data.redis.core.RedisTemplate; | |
| 7 | +import org.springframework.data.redis.core.ScanOptions; | |
| 8 | + | |
| 9 | +import java.util.ArrayList; | |
| 10 | +import java.util.HashSet; | |
| 11 | +import java.util.List; | |
| 12 | +import java.util.Set; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * Redis工具类 | |
| 16 | + * | |
| 17 | + * @author swwheihei | |
| 18 | + * @date 2020年5月6日 下午8:27:29 | |
| 19 | + */ | |
| 20 | +@SuppressWarnings(value = {"rawtypes", "unchecked"}) | |
| 21 | +public class RedisUtil { | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 模糊查询 | |
| 25 | + * | |
| 26 | + * @param query 查询参数 | |
| 27 | + * @return | |
| 28 | + */ | |
| 29 | + public static List<Object> scan(RedisTemplate redisTemplate, String query) { | |
| 30 | + | |
| 31 | + Set<String> resultKeys = (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> { | |
| 32 | + ScanOptions scanOptions = ScanOptions.scanOptions().match("*" + query + "*").count(1000).build(); | |
| 33 | + Cursor<byte[]> scan = connection.scan(scanOptions); | |
| 34 | + Set<String> keys = new HashSet<>(); | |
| 35 | + while (scan.hasNext()) { | |
| 36 | + byte[] next = scan.next(); | |
| 37 | + keys.add(new String(next)); | |
| 38 | + } | |
| 39 | + return keys; | |
| 40 | + }); | |
| 41 | + | |
| 42 | + return Lists.newArrayList(resultKeys); | |
| 43 | + } | |
| 44 | +} | |
| 45 | + | |
| 46 | + | |
| 47 | + | ... | ... |
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil2.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/BaseTree.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/BatchGBStreamParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultEx.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultFilter.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/OtherPsSendInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/OtherRtpSendInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/PageInfo.java
0 → 100755
| 1 | +package com.genersoft.iot.vmp.vmanager.bean; | |
| 2 | + | |
| 3 | +import java.util.ArrayList; | |
| 4 | +import java.util.List; | |
| 5 | + | |
| 6 | +public class PageInfo<T> { | |
| 7 | + //当前页 | |
| 8 | + private int pageNum; | |
| 9 | + //每页的数量 | |
| 10 | + private int pageSize; | |
| 11 | + //当前页的数量 | |
| 12 | + private int size; | |
| 13 | + //总页数 | |
| 14 | + private int pages; | |
| 15 | + //总数 | |
| 16 | + private int total; | |
| 17 | + | |
| 18 | + private List<T> resultData; | |
| 19 | + | |
| 20 | + private List<T> list; | |
| 21 | + | |
| 22 | + public PageInfo(List<T> resultData) { | |
| 23 | + this.resultData = resultData; | |
| 24 | + } | |
| 25 | + | |
| 26 | + public PageInfo() { | |
| 27 | + } | |
| 28 | + | |
| 29 | + public void startPage(int page, int count) { | |
| 30 | + if (count <= 0) count = 10; | |
| 31 | + if (page <= 0) page = 1; | |
| 32 | + this.pageNum = page; | |
| 33 | + this.pageSize = count; | |
| 34 | + this.total = resultData.size(); | |
| 35 | + | |
| 36 | + this.pages = total % count == 0 ? total / count : total / count + 1; | |
| 37 | + int fromIndx = (page - 1) * count; | |
| 38 | + if (fromIndx > this.total - 1) { | |
| 39 | + this.list = new ArrayList<>(); | |
| 40 | + this.size = 0; | |
| 41 | + return; | |
| 42 | + } | |
| 43 | + | |
| 44 | + int toIndx = page * count; | |
| 45 | + if (toIndx > this.total) { | |
| 46 | + toIndx = this.total; | |
| 47 | + } | |
| 48 | + this.list = this.resultData.subList(fromIndx, toIndx); | |
| 49 | + this.size = this.list.size(); | |
| 50 | + } | |
| 51 | + | |
| 52 | + public int getPageNum() { | |
| 53 | + return pageNum; | |
| 54 | + } | |
| 55 | + | |
| 56 | + public void setPageNum(int pageNum) { | |
| 57 | + this.pageNum = pageNum; | |
| 58 | + } | |
| 59 | + | |
| 60 | + public int getPageSize() { | |
| 61 | + return pageSize; | |
| 62 | + } | |
| 63 | + | |
| 64 | + public void setPageSize(int pageSize) { | |
| 65 | + this.pageSize = pageSize; | |
| 66 | + } | |
| 67 | + | |
| 68 | + public int getSize() { | |
| 69 | + return size; | |
| 70 | + } | |
| 71 | + | |
| 72 | + public void setSize(int size) { | |
| 73 | + this.size = size; | |
| 74 | + } | |
| 75 | + | |
| 76 | + public int getPages() { | |
| 77 | + return pages; | |
| 78 | + } | |
| 79 | + | |
| 80 | + public void setPages(int pages) { | |
| 81 | + this.pages = pages; | |
| 82 | + } | |
| 83 | + | |
| 84 | + public int getTotal() { | |
| 85 | + return total; | |
| 86 | + } | |
| 87 | + | |
| 88 | + public void setTotal(int total) { | |
| 89 | + this.total = total; | |
| 90 | + } | |
| 91 | + | |
| 92 | + public List<T> getList() { | |
| 93 | + return list; | |
| 94 | + } | |
| 95 | + | |
| 96 | + public void setList(List<T> list) { | |
| 97 | + this.list = list; | |
| 98 | + } | |
| 99 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/PlayTypeEnum.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/RecordFile.java
0 → 100755
| 1 | +package com.genersoft.iot.vmp.vmanager.bean; | |
| 2 | + | |
| 3 | +public class RecordFile { | |
| 4 | + private String app; | |
| 5 | + private String stream; | |
| 6 | + | |
| 7 | + private String fileName; | |
| 8 | + | |
| 9 | + private String mediaServerId; | |
| 10 | + | |
| 11 | + private String date; | |
| 12 | + | |
| 13 | + | |
| 14 | + public String getApp() { | |
| 15 | + return app; | |
| 16 | + } | |
| 17 | + | |
| 18 | + public void setApp(String app) { | |
| 19 | + this.app = app; | |
| 20 | + } | |
| 21 | + | |
| 22 | + public String getStream() { | |
| 23 | + return stream; | |
| 24 | + } | |
| 25 | + | |
| 26 | + public void setStream(String stream) { | |
| 27 | + this.stream = stream; | |
| 28 | + } | |
| 29 | + | |
| 30 | + public String getFileName() { | |
| 31 | + return fileName; | |
| 32 | + } | |
| 33 | + | |
| 34 | + public void setFileName(String fileName) { | |
| 35 | + this.fileName = fileName; | |
| 36 | + } | |
| 37 | + | |
| 38 | + public String getMediaServerId() { | |
| 39 | + return mediaServerId; | |
| 40 | + } | |
| 41 | + | |
| 42 | + public void setMediaServerId(String mediaServerId) { | |
| 43 | + this.mediaServerId = mediaServerId; | |
| 44 | + } | |
| 45 | + | |
| 46 | + public String getDate() { | |
| 47 | + return date; | |
| 48 | + } | |
| 49 | + | |
| 50 | + public void setDate(String date) { | |
| 51 | + this.date = date; | |
| 52 | + } | |
| 53 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceBaseInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/SnapPath.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamPushExcelDto.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/SystemConfigInfo.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java
0 → 100755
| 1 | +package com.genersoft.iot.vmp.vmanager.cloudRecord; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.conf.DynamicTask; | |
| 4 | +import com.genersoft.iot.vmp.conf.UserSetting; | |
| 5 | +import com.genersoft.iot.vmp.conf.exception.ControllerException; | |
| 6 | +import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager; | |
| 7 | +import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; | |
| 8 | +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | |
| 9 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 10 | +import com.genersoft.iot.vmp.service.IMediaServerService; | |
| 11 | +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | |
| 12 | +import com.genersoft.iot.vmp.vmanager.bean.PageInfo; | |
| 13 | +import com.genersoft.iot.vmp.vmanager.bean.RecordFile; | |
| 14 | +import io.swagger.v3.oas.annotations.Operation; | |
| 15 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 16 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 17 | +import org.apache.commons.lang3.ObjectUtils; | |
| 18 | +import org.slf4j.Logger; | |
| 19 | +import org.slf4j.LoggerFactory; | |
| 20 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 21 | +import org.springframework.data.redis.core.RedisTemplate; | |
| 22 | +import org.springframework.web.bind.annotation.*; | |
| 23 | + | |
| 24 | +import java.util.ArrayList; | |
| 25 | +import java.util.Calendar; | |
| 26 | +import java.util.List; | |
| 27 | + | |
| 28 | +@SuppressWarnings("rawtypes") | |
| 29 | +@Tag(name = "云端录像接口") | |
| 30 | + | |
| 31 | +@RestController | |
| 32 | +@RequestMapping("/api/cloud/record") | |
| 33 | +public class CloudRecordController { | |
| 34 | + | |
| 35 | + @Autowired | |
| 36 | + private ZLMServerFactory zlmServerFactory; | |
| 37 | + | |
| 38 | + @Autowired | |
| 39 | + private SendRtpPortManager sendRtpPortManager; | |
| 40 | + | |
| 41 | + private final static Logger logger = LoggerFactory.getLogger(CloudRecordController.class); | |
| 42 | + | |
| 43 | + @Autowired | |
| 44 | + private ZlmHttpHookSubscribe hookSubscribe; | |
| 45 | + | |
| 46 | + @Autowired | |
| 47 | + private IMediaServerService mediaServerService; | |
| 48 | + | |
| 49 | + @Autowired | |
| 50 | + private UserSetting userSetting; | |
| 51 | + | |
| 52 | + @Autowired | |
| 53 | + private DynamicTask dynamicTask; | |
| 54 | + | |
| 55 | + @Autowired | |
| 56 | + private RedisTemplate<Object, Object> redisTemplate; | |
| 57 | + | |
| 58 | + @ResponseBody | |
| 59 | + @GetMapping("/date/list") | |
| 60 | + @Operation(summary = "查询存在云端录像的日期") | |
| 61 | + @Parameter(name = "app", description = "应用名", required = true) | |
| 62 | + @Parameter(name = "stream", description = "流ID", required = true) | |
| 63 | + @Parameter(name = "year", description = "年,置空则查询当年", required = false) | |
| 64 | + @Parameter(name = "month", description = "月,置空则查询当月", required = false) | |
| 65 | + @Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部", required = false) | |
| 66 | + public List<String> openRtpServer( | |
| 67 | + @RequestParam String app, | |
| 68 | + @RequestParam String stream, | |
| 69 | + @RequestParam(required = false) int year, | |
| 70 | + @RequestParam(required = false) int month, | |
| 71 | + @RequestParam(required = false) String mediaServerId | |
| 72 | + | |
| 73 | + ) { | |
| 74 | + logger.info("[云端录像] 查询存在云端录像的日期 app->{}, stream->{}, mediaServerId->{}, year->{}, month->{}", | |
| 75 | + app, stream, mediaServerId, year, month); | |
| 76 | + Calendar calendar = Calendar.getInstance(); | |
| 77 | + if (ObjectUtils.isEmpty(year)) { | |
| 78 | + year = calendar.get(Calendar.YEAR); | |
| 79 | + } | |
| 80 | + if (ObjectUtils.isEmpty(month)) { | |
| 81 | + month = calendar.get(Calendar.MONTH) + 1; | |
| 82 | + } | |
| 83 | + List<MediaServerItem> mediaServerItems; | |
| 84 | + if (!ObjectUtils.isEmpty(mediaServerId)) { | |
| 85 | + mediaServerItems = new ArrayList<>(); | |
| 86 | + MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); | |
| 87 | + if (mediaServerItem == null) { | |
| 88 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体: " + mediaServerId); | |
| 89 | + } | |
| 90 | + mediaServerItems.add(mediaServerItem); | |
| 91 | + } else { | |
| 92 | + mediaServerItems = mediaServerService.getAll(); | |
| 93 | + } | |
| 94 | + if (mediaServerItems.isEmpty()) { | |
| 95 | + return new ArrayList<>(); | |
| 96 | + } | |
| 97 | + | |
| 98 | + return mediaServerService.getRecordDates(app, stream, year, month, mediaServerItems); | |
| 99 | + } | |
| 100 | + | |
| 101 | + @ResponseBody | |
| 102 | + @GetMapping("/list") | |
| 103 | + @Operation(summary = "分页查询云端录像") | |
| 104 | + @Parameter(name = "app", description = "应用名", required = true) | |
| 105 | + @Parameter(name = "stream", description = "流ID", required = true) | |
| 106 | + @Parameter(name = "page", description = "当前页", required = false) | |
| 107 | + @Parameter(name = "count", description = "每页查询数量", required = false) | |
| 108 | + @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true) | |
| 109 | + @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true) | |
| 110 | + @Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部流媒体", required = false) | |
| 111 | + public PageInfo<RecordFile> openRtpServer( | |
| 112 | + @RequestParam String app, | |
| 113 | + @RequestParam String stream, | |
| 114 | + @RequestParam int page, | |
| 115 | + @RequestParam int count, | |
| 116 | + @RequestParam String startTime, | |
| 117 | + @RequestParam String endTime, | |
| 118 | + @RequestParam(required = false) String mediaServerId | |
| 119 | + | |
| 120 | + ) { | |
| 121 | + logger.info("[云端录像] 查询 app->{}, stream->{}, mediaServerId->{}, page->{}, count->{}, startTime->{}, endTime->{}", | |
| 122 | + app, stream, mediaServerId, page, count, startTime, endTime); | |
| 123 | + | |
| 124 | + List<MediaServerItem> mediaServerItems; | |
| 125 | + if (!ObjectUtils.isEmpty(mediaServerId)) { | |
| 126 | + mediaServerItems = new ArrayList<>(); | |
| 127 | + MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); | |
| 128 | + if (mediaServerItem == null) { | |
| 129 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体: " + mediaServerId); | |
| 130 | + } | |
| 131 | + mediaServerItems.add(mediaServerItem); | |
| 132 | + } else { | |
| 133 | + mediaServerItems = mediaServerService.getAll(); | |
| 134 | + } | |
| 135 | + if (mediaServerItems.isEmpty()) { | |
| 136 | + return new PageInfo<>(); | |
| 137 | + } | |
| 138 | + List<RecordFile> records = mediaServerService.getRecords(app, stream, startTime, endTime, mediaServerItems); | |
| 139 | + PageInfo<RecordFile> pageInfo = new PageInfo<>(records); | |
| 140 | + pageInfo.startPage(page, count); | |
| 141 | + return pageInfo; | |
| 142 | + } | |
| 143 | + | |
| 144 | + | |
| 145 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/SseController/SseController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/bean/PlayResult.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java
100644 → 100755
| ... | ... | @@ -91,10 +91,10 @@ public class PsController { |
| 91 | 91 | if (isSend != null && isSend && callId == null) { |
| 92 | 92 | throw new ControllerException(ErrorCode.ERROR100.getCode(),"isSend为true时,CallID不能为空"); |
| 93 | 93 | } |
| 94 | - int ssrcInt = 0; | |
| 94 | + long ssrcInt = 0; | |
| 95 | 95 | if (ssrc != null) { |
| 96 | 96 | try { |
| 97 | - ssrcInt = Integer.parseInt(ssrc); | |
| 97 | + ssrcInt = Long.parseLong(ssrc); | |
| 98 | 98 | }catch (NumberFormatException e) { |
| 99 | 99 | throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误"); |
| 100 | 100 | } |
| ... | ... | @@ -223,8 +223,6 @@ public class PsController { |
| 223 | 223 | String is_Udp = isUdp ? "1" : "0"; |
| 224 | 224 | param.put("is_udp", is_Udp); |
| 225 | 225 | param.put("src_port", sendInfo.getSendLocalPort()); |
| 226 | - param.put("use_ps", "0"); | |
| 227 | - param.put("only_audio", "1"); | |
| 228 | 226 | |
| 229 | 227 | |
| 230 | 228 | Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, app, stream); | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java
100644 → 100755
| ... | ... | @@ -91,10 +91,10 @@ public class RtpController { |
| 91 | 91 | if (isSend != null && isSend && callId == null) { |
| 92 | 92 | throw new ControllerException(ErrorCode.ERROR100.getCode(),"isSend为true时,CallID不能为空"); |
| 93 | 93 | } |
| 94 | - int ssrcInt = 0; | |
| 94 | + long ssrcInt = 0; | |
| 95 | 95 | if (ssrc != null) { |
| 96 | 96 | try { |
| 97 | - ssrcInt = Integer.parseInt(ssrc); | |
| 97 | + ssrcInt = Long.parseLong(ssrc); | |
| 98 | 98 | }catch (NumberFormatException e) { |
| 99 | 99 | throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误"); |
| 100 | 100 | } |
| ... | ... | @@ -247,7 +247,6 @@ public class RtpController { |
| 247 | 247 | String is_Udp = isUdp ? "1" : "0"; |
| 248 | 248 | paramForAudio.put("is_udp", is_Udp); |
| 249 | 249 | paramForAudio.put("src_port", sendInfo.getSendLocalPortForAudio()); |
| 250 | - paramForAudio.put("use_ps", "0"); | |
| 251 | 250 | paramForAudio.put("only_audio", "1"); |
| 252 | 251 | if (ptForAudio != null) { |
| 253 | 252 | paramForAudio.put("pt", ptForAudio); |
| ... | ... | @@ -268,7 +267,6 @@ public class RtpController { |
| 268 | 267 | String is_Udp = isUdp ? "1" : "0"; |
| 269 | 268 | paramForVideo.put("is_udp", is_Udp); |
| 270 | 269 | paramForVideo.put("src_port", sendInfo.getSendLocalPortForVideo()); |
| 271 | - paramForVideo.put("use_ps", "0"); | |
| 272 | 270 | paramForVideo.put("only_audio", "0"); |
| 273 | 271 | if (ptForVideo != null) { |
| 274 | 272 | paramForVideo.put("pt", ptForVideo); | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/user/RoleController.java
100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
100644 → 100755
src/main/resources/all-application.yml
web_src/src/App.vue
100644 → 100755
web_src/src/assets/icons.png
100644 → 100755
web_src/src/assets/loading.png
100644 → 100755
web_src/src/assets/login-bg.jpg
100644 → 100755
web_src/src/assets/login-cloud.png
100644 → 100755
web_src/src/assets/logo.png
100644 → 100755
web_src/src/assets/play.png
100644 → 100755
web_src/src/assets/zlm-log.png
100644 → 100755
web_src/src/components/CloudRecord.vue
100644 → 100755
| ... | ... | @@ -47,19 +47,17 @@ |
| 47 | 47 | :total="total"> |
| 48 | 48 | </el-pagination> |
| 49 | 49 | </div> |
| 50 | - <cloud-record-detail ref="cloudRecordDetail" v-if="recordDetail" :recordFile="chooseRecord" :mediaServerId="mediaServerId" :mediaServerPath="mediaServerPath" ></cloud-record-detail> | |
| 51 | 50 | |
| 52 | 51 | </div> |
| 53 | 52 | </template> |
| 54 | 53 | |
| 55 | 54 | <script> |
| 56 | 55 | import uiHeader from '../layout/UiHeader.vue' |
| 57 | - import cloudRecordDetail from './CloudRecordDetail.vue' | |
| 58 | 56 | import MediaServer from './service/MediaServer' |
| 59 | 57 | export default { |
| 60 | 58 | name: 'app', |
| 61 | 59 | components: { |
| 62 | - uiHeader, cloudRecordDetail | |
| 60 | + uiHeader | |
| 63 | 61 | }, |
| 64 | 62 | data() { |
| 65 | 63 | return { |
| ... | ... | @@ -178,7 +176,7 @@ |
| 178 | 176 | // }).catch(function (error) { |
| 179 | 177 | // console.log(error); |
| 180 | 178 | // }); |
| 181 | - | |
| 179 | + this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`) | |
| 182 | 180 | }, |
| 183 | 181 | deleteRecord(){ |
| 184 | 182 | // TODO | ... | ... |
web_src/src/components/CloudRecordDetail.vue
100644 → 100755
| 1 | 1 | <template> |
| 2 | - <div id="recordDetail"> | |
| 3 | - <el-container> | |
| 2 | + <div id="recordDetail" style="width: 100%"> | |
| 3 | + <div class="page-header" style="margin-bottom: 0"> | |
| 4 | + <div class="page-title"> | |
| 5 | + <el-page-header @back="backToList" content="云端录像"></el-page-header> | |
| 6 | + </div> | |
| 7 | + | |
| 8 | + <div class="page-header-btn" v-if="!this.$route.params.mediaServerId" style="padding-right: 1rem"> | |
| 9 | + <!-- 节点选择:--> | |
| 10 | + <!-- <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServerId" placeholder="请选择" >--> | |
| 11 | + <!-- <el-option--> | |
| 12 | + <!-- key="undefined"--> | |
| 13 | + <!-- label="全部"--> | |
| 14 | + <!-- value="undefined">--> | |
| 15 | + <!-- </el-option>--> | |
| 16 | + <!-- <el-option--> | |
| 17 | + <!-- v-for="item in mediaServerList"--> | |
| 18 | + <!-- :key="item"--> | |
| 19 | + <!-- :label="item"--> | |
| 20 | + <!-- :value="item">--> | |
| 21 | + <!-- </el-option>--> | |
| 22 | + <!-- </el-select>--> | |
| 23 | + <b>节点:</b> {{ mediaServerId }} | |
| 24 | + </div> | |
| 25 | + <div v-if="this.$route.params.mediaServerId" style="margin-right: 1rem;"> | |
| 26 | + <span>流媒体:{{ this.$route.params.mediaServerId }}</span> | |
| 27 | + </div> | |
| 28 | + </div> | |
| 29 | + <el-container> | |
| 4 | 30 | <el-aside width="260px"> |
| 5 | 31 | <div class="record-list-box-box"> |
| 6 | 32 | <div style="margin-top: 20px"> |
| 7 | - <el-date-picker size="mini" style="width: 160px" v-model="chooseDate" :picker-options="pickerOptions" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="dateChange()"></el-date-picker> | |
| 8 | - <el-button size="mini" type="primary" icon="fa fa-cloud-download" style="margin: auto; margin-left: 12px " title="裁剪合并" @click="drawerOpen"></el-button> | |
| 33 | + <el-date-picker size="mini" v-model="chooseDate" :picker-options="pickerOptions" type="date" | |
| 34 | + value-format="yyyy-MM-dd" placeholder="日期" @change="dateChange()"></el-date-picker> | |
| 35 | + <!-- <el-button :disabled="!mediaServerId" size="mini" type="primary" icon="fa fa-cloud-download" style="margin: auto; margin-left: 12px " title="裁剪合并" @click="drawerOpen"></el-button>--> | |
| 9 | 36 | </div> |
| 10 | 37 | <div class="record-list-box" :style="recordListStyle"> |
| 11 | 38 | <ul v-if="detailFiles.length >0" class="infinite-list record-list" v-infinite-scroll="infiniteScroll" > |
| 12 | 39 | <li v-for="(item,index) in detailFiles" :key="index" class="infinite-list-item record-list-item" > |
| 13 | - <el-tag v-if="choosedFile != item" @click="chooseFile(item)"> | |
| 40 | + <el-tag v-if="choosedFile !== item.filename" @click="chooseFile(item)"> | |
| 14 | 41 | <i class="el-icon-video-camera" ></i> |
| 15 | - {{ item.substring(0,17)}} | |
| 42 | + {{ getFileShowName(item.fileName) }} | |
| 16 | 43 | </el-tag> |
| 17 | - <el-tag type="danger" v-if="choosedFile == item"> | |
| 44 | + <el-tag type="danger" v-if="choosedFile === item.filename"> | |
| 18 | 45 | <i class="el-icon-video-camera" ></i> |
| 19 | - {{ item.substring(0,17)}} | |
| 46 | + {{ getFileShowName(item.fileName) }} | |
| 20 | 47 | </el-tag> |
| 21 | - <a class="el-icon-download" style="color: #409EFF;font-weight: 600;margin-left: 10px;" :href="`${getFileBasePath()}/download.html?url=download/${recordFile.app}/${recordFile.stream}/${chooseDate}/${item}`" target="_blank" /> | |
| 48 | + <a class="el-icon-download" style="color: #409EFF;font-weight: 600;margin-left: 10px;" | |
| 49 | + :href="`${getFileBasePath(item)}/download.html?url=download/${app}/${stream}/${chooseDate}/${item.fileName}`" | |
| 50 | + target="_blank"/> | |
| 22 | 51 | </li> |
| 23 | 52 | </ul> |
| 24 | 53 | </div> |
| 25 | - <div v-if="detailFiles.length ==0" class="record-list-no-val" >暂无数据</div> | |
| 54 | + <div v-if="detailFiles.length === 0" class="record-list-no-val">暂无数据</div> | |
| 26 | 55 | </div> |
| 27 | 56 | |
| 28 | 57 | |
| 29 | 58 | </el-aside> |
| 30 | - <el-main style="padding: 22px"> | |
| 59 | + <el-main style="padding: 22px"> | |
| 31 | 60 | <div class="playBox" :style="playerStyle"> |
| 32 | 61 | <player ref="recordVideoPlayer" :videoUrl="videoUrl" :height="true" style="width: 100%" ></player> |
| 33 | 62 | </div> |
| ... | ... | @@ -48,8 +77,8 @@ |
| 48 | 77 | </div> |
| 49 | 78 | </div> |
| 50 | 79 | |
| 51 | - </el-main> | |
| 52 | - </el-container> | |
| 80 | + </el-main> | |
| 81 | + </el-container> | |
| 53 | 82 | <el-drawer |
| 54 | 83 | title="录像下载" |
| 55 | 84 | :visible.sync="drawer" |
| ... | ... | @@ -76,7 +105,8 @@ |
| 76 | 105 | <li class="task-list-item" v-for="(item, index) in taskListEnded" :key="index"> |
| 77 | 106 | <div class="task-list-item-box" style="height: 2rem;line-height: 2rem;"> |
| 78 | 107 | <span>{{ item.startTime.substr(10) }}-{{item.endTime.substr(10)}}</span> |
| 79 | - <a class="el-icon-download download-btn" :href="getFileBasePath() + '/download.html?url=download/' + item.recordFile" target="_blank"> | |
| 108 | + <a class="el-icon-download download-btn" :href="getFileBasePath() + '/download.html?url=download/' " | |
| 109 | + target="_blank"> | |
| 80 | 110 | </a> |
| 81 | 111 | </div> |
| 82 | 112 | </li> |
| ... | ... | @@ -113,11 +143,16 @@ |
| 113 | 143 | components: { |
| 114 | 144 | uiHeader, player |
| 115 | 145 | }, |
| 116 | - props: ['recordFile', 'mediaServerId', 'dateFiles'], | |
| 146 | + // props: [ 'mediaServerId',], | |
| 117 | 147 | data() { |
| 118 | 148 | return { |
| 149 | + app: this.$route.params.app, | |
| 150 | + stream: this.$route.params.stream, | |
| 151 | + mediaServerId: this.$route.params.mediaServerId, | |
| 119 | 152 | dateFilesObj: [], |
| 153 | + mediaServerList: [], | |
| 120 | 154 | detailFiles: [], |
| 155 | + loading: false, | |
| 121 | 156 | chooseDate: null, |
| 122 | 157 | videoUrl: null, |
| 123 | 158 | choosedFile: null, |
| ... | ... | @@ -195,6 +230,9 @@ |
| 195 | 230 | mounted() { |
| 196 | 231 | this.recordListStyle.height = this.winHeight + "px"; |
| 197 | 232 | this.playerStyle["height"] = this.winHeight + "px"; |
| 233 | + console.log(this.app) | |
| 234 | + console.log(this.stream) | |
| 235 | + console.log(this.mediaServerId) | |
| 198 | 236 | // 查询当年有视频的日期 |
| 199 | 237 | this.getDateInYear(()=>{ |
| 200 | 238 | if (Object.values(this.dateFilesObj).length > 0){ |
| ... | ... | @@ -216,7 +254,8 @@ |
| 216 | 254 | let chooseFullDate = new Date(this.chooseDate +" " + this.timeFormat); |
| 217 | 255 | if (chooseFullDate.getFullYear() !== this.queryDate.getFullYear() |
| 218 | 256 | || chooseFullDate.getMonth() !== this.queryDate.getMonth()){ |
| 219 | - // this.getDateInYear() | |
| 257 | + this.queryDate = chooseFullDate; | |
| 258 | + this.getDateInYear() | |
| 220 | 259 | } |
| 221 | 260 | this.queryRecordDetails(()=>{ |
| 222 | 261 | if (this.detailFiles.length > 0){ |
| ... | ... | @@ -242,48 +281,69 @@ |
| 242 | 281 | } |
| 243 | 282 | }, |
| 244 | 283 | queryRecordDetails: function (callback){ |
| 245 | - let that = this; | |
| 246 | - that.$axios({ | |
| 284 | + this.$axios({ | |
| 247 | 285 | method: 'get', |
| 248 | - url:`/record_proxy/${that.mediaServerId}/api/record/file/list`, | |
| 286 | + url: `/api/cloud/record/list`, | |
| 249 | 287 | params: { |
| 250 | - app: that.recordFile.app, | |
| 251 | - stream: that.recordFile.stream, | |
| 252 | - startTime: that.chooseDate + " 00:00:00", | |
| 253 | - endTime: that.chooseDate + " 23:59:59", | |
| 254 | - page: that.currentPage, | |
| 255 | - count: that.count | |
| 288 | + app: this.app, | |
| 289 | + stream: this.stream, | |
| 290 | + startTime: this.chooseDate + " 00:00:00", | |
| 291 | + endTime: this.chooseDate + " 23:59:59", | |
| 292 | + page: this.currentPage, | |
| 293 | + count: this.count, | |
| 294 | + mediaServerId: this.mediaServerId | |
| 256 | 295 | } |
| 257 | - }).then(function (res) { | |
| 296 | + }).then((res) => { | |
| 258 | 297 | if (res.data.code === 0) { |
| 259 | - that.total = res.data.data.total; | |
| 260 | - that.detailFiles = that.detailFiles.concat(res.data.data.list); | |
| 298 | + this.total = res.data.data.total; | |
| 299 | + this.detailFiles = this.detailFiles.concat(res.data.data.list); | |
| 300 | + let temp = new Set() | |
| 301 | + for (let i = 0; i < this.detailFiles.length; i++) { | |
| 302 | + temp.add(this.detailFiles[i].mediaServerId) | |
| 303 | + } | |
| 304 | + this.mediaServerList = Array.from(temp) | |
| 305 | + if (this.mediaServerList.length === 1) { | |
| 306 | + this.mediaServerId = this.mediaServerList[0] | |
| 307 | + } | |
| 261 | 308 | } |
| 262 | - that.loading = false; | |
| 309 | + this.loading = false; | |
| 263 | 310 | if (callback) callback(); |
| 264 | - }).catch(function (error) { | |
| 311 | + }).catch((error) => { | |
| 265 | 312 | console.log(error); |
| 266 | - that.loading = false; | |
| 313 | + this.loading = false; | |
| 267 | 314 | }); |
| 268 | 315 | }, |
| 269 | 316 | chooseFile(file){ |
| 270 | - this.choosedFile = file; | |
| 271 | 317 | if (file == null) { |
| 272 | 318 | this.videoUrl = ""; |
| 319 | + this.choosedFile = ""; | |
| 273 | 320 | }else { |
| 274 | - this.videoUrl = `${this.getFileBasePath()}/download/${this.recordFile.app}/${this.recordFile.stream}/${this.chooseDate}/${this.choosedFile}` | |
| 275 | - | |
| 321 | + this.choosedFile = file.fileName; | |
| 322 | + this.videoUrl = `${this.getFileBasePath(file)}/download/${this.app}/${this.stream}/${this.chooseDate}/${this.choosedFile}` | |
| 276 | 323 | console.log(this.videoUrl) |
| 277 | 324 | } |
| 278 | 325 | |
| 279 | 326 | }, |
| 327 | + backToList() { | |
| 328 | + this.$router.back() | |
| 329 | + }, | |
| 330 | + getFileShowName(name) { | |
| 331 | + return name.substring(0, 2) + ":" + name.substring(2, 4) + ":" + name.substring(4, 6) + "-" + | |
| 332 | + name.substring(7, 9) + ":" + name.substring(9, 11) + ":" + name.substring(11, 13) | |
| 333 | + }, | |
| 334 | + chooseMediaChange() { | |
| 335 | + | |
| 336 | + }, | |
| 337 | + getRecordList() { | |
| 280 | 338 | |
| 281 | - getFileBasePath(){ | |
| 339 | + }, | |
| 340 | + | |
| 341 | + getFileBasePath(item) { | |
| 282 | 342 | let basePath = "" |
| 283 | 343 | if (axios.defaults.baseURL.startsWith("http")) { |
| 284 | - basePath = `${axios.defaults.baseURL}/record_proxy/${this.mediaServerId}` | |
| 344 | + basePath = `${axios.defaults.baseURL}/record_proxy/${item.mediaServerId}` | |
| 285 | 345 | }else { |
| 286 | - basePath = `${window.location.origin}${axios.defaults.baseURL}/record_proxy/${this.mediaServerId}` | |
| 346 | + basePath = `${window.location.origin}${axios.defaults.baseURL}/record_proxy/${item.mediaServerId}` | |
| 287 | 347 | } |
| 288 | 348 | return basePath; |
| 289 | 349 | }, |
| ... | ... | @@ -316,7 +376,7 @@ |
| 316 | 376 | }, |
| 317 | 377 | getTimeForFile(file){ |
| 318 | 378 | console.log(file) |
| 319 | - let timeStr = file.substring(0,17); | |
| 379 | + let timeStr = file.fileName.substring(0, 17); | |
| 320 | 380 | if(timeStr.indexOf("~") > 0){ |
| 321 | 381 | timeStr = timeStr.replaceAll("-",":") |
| 322 | 382 | } |
| ... | ... | @@ -370,27 +430,30 @@ |
| 370 | 430 | }); |
| 371 | 431 | }, |
| 372 | 432 | getDateInYear(callback){ |
| 373 | - let that = this; | |
| 374 | - that.dateFilesObj = {}; | |
| 433 | + this.dateFilesObj = {}; | |
| 375 | 434 | this.$axios({ |
| 376 | 435 | method: 'get', |
| 377 | - url:`/record_proxy/${that.mediaServerId}/api/record/date/list`, | |
| 436 | + url: `/api/cloud/record/date/list`, | |
| 378 | 437 | params: { |
| 379 | - app: that.recordFile.app, | |
| 380 | - stream: that.recordFile.stream | |
| 438 | + app: this.app, | |
| 439 | + stream: this.stream, | |
| 440 | + year: this.queryDate.getFullYear(), | |
| 441 | + month: this.queryDate.getMonth() + 1, | |
| 442 | + mediaServerId: this.mediaServerId, | |
| 381 | 443 | } |
| 382 | - }).then(function (res) { | |
| 444 | + }).then((res) => { | |
| 445 | + console.log(res) | |
| 383 | 446 | if (res.data.code === 0) { |
| 384 | 447 | if (res.data.data.length > 0) { |
| 385 | 448 | for (let i = 0; i < res.data.data.length; i++) { |
| 386 | - that.dateFilesObj[res.data.data[i]] = res.data.data[i] | |
| 449 | + this.dateFilesObj[res.data.data[i]] = res.data.data[i] | |
| 387 | 450 | } |
| 388 | 451 | |
| 389 | - console.log(that.dateFilesObj) | |
| 452 | + console.log(this.dateFilesObj) | |
| 390 | 453 | } |
| 391 | 454 | } |
| 392 | 455 | if(callback)callback(); |
| 393 | - }).catch(function (error) { | |
| 456 | + }).catch((error) => { | |
| 394 | 457 | console.log(error); |
| 395 | 458 | }); |
| 396 | 459 | }, |
| ... | ... | @@ -414,8 +477,8 @@ |
| 414 | 477 | }, |
| 415 | 478 | addTask(){ |
| 416 | 479 | this.showTaskBox = true; |
| 417 | - let startTimeStr = this.chooseDate + " " + this.detailFiles[0].substring(0,8); | |
| 418 | - let endTimeStr = this.chooseDate + " " + this.detailFiles[this.detailFiles.length - 1].substring(9,17); | |
| 480 | + let startTimeStr = this.chooseDate + " " + this.detailFiles[0].fileName.substring(0, 8); | |
| 481 | + let endTimeStr = this.chooseDate + " " + this.detailFiles[this.detailFiles.length - 1].fileName.substring(9, 17); | |
| 419 | 482 | this.taskTimeRange[0] = new Date(startTimeStr) |
| 420 | 483 | this.taskTimeRange[1] = new Date(endTimeStr) |
| 421 | 484 | }, |
| ... | ... | @@ -425,8 +488,8 @@ |
| 425 | 488 | method: 'get', |
| 426 | 489 | url:`/record_proxy/${that.mediaServerId}/api/record/file/download/task/add`, |
| 427 | 490 | params: { |
| 428 | - app: that.recordFile.app, | |
| 429 | - stream: that.recordFile.stream, | |
| 491 | + app: that.app, | |
| 492 | + stream: that.stream, | |
| 430 | 493 | startTime: moment(this.taskTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'), |
| 431 | 494 | endTime: moment(this.taskTimeRange[1]).format('YYYY-MM-DD HH:mm:ss'), |
| 432 | 495 | } | ... | ... |
web_src/src/components/DeviceList.vue
100644 → 100755
web_src/src/components/GBRecordDetail.vue
100644 → 100755
web_src/src/components/GeoConvertTools.js
100644 → 100755
web_src/src/components/Login.vue
100644 → 100755
web_src/src/components/MediaServerManger.vue
100644 → 100755
web_src/src/components/ParentPlatformList.vue
100644 → 100755
web_src/src/components/PushVideoList.vue
100644 → 100755
| ... | ... | @@ -89,6 +89,8 @@ |
| 89 | 89 | <el-button size="medium" icon="el-icon-position" type="text" v-if="!!scope.row.gbId" |
| 90 | 90 | @click="removeFromGB(scope.row)">移出国标 |
| 91 | 91 | </el-button> |
| 92 | + <el-button size="medium" icon="el-icon-cloudy" type="text" @click="queryCloudRecords(scope.row)">云端录像 | |
| 93 | + </el-button> | |
| 92 | 94 | </template> |
| 93 | 95 | </el-table-column> |
| 94 | 96 | </el-table> |
| ... | ... | @@ -257,6 +259,10 @@ export default { |
| 257 | 259 | console.error(error); |
| 258 | 260 | }); |
| 259 | 261 | }, |
| 262 | + queryCloudRecords: function (row) { | |
| 263 | + | |
| 264 | + this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`) | |
| 265 | + }, | |
| 260 | 266 | importChannel: function () { |
| 261 | 267 | this.$refs.importChannel.openDialog(() => { |
| 262 | 268 | ... | ... |
web_src/src/components/StreamProxyList.vue
100644 → 100755
| ... | ... | @@ -91,6 +91,8 @@ |
| 91 | 91 | <el-button size="medium" icon="el-icon-check" type="text" :loading="scope.row.startBtnLoading" v-if="!scope.row.enable" @click="start(scope.row)">启用</el-button> |
| 92 | 92 | <el-divider v-if="!scope.row.enable" direction="vertical"></el-divider> |
| 93 | 93 | <el-button size="medium" icon="el-icon-delete" type="text" style="color: #f56c6c" @click="deleteStreamProxy(scope.row)">删除</el-button> |
| 94 | + <el-button size="medium" icon="el-icon-cloudy" type="text" @click="queryCloudRecords(scope.row)">云端录像 | |
| 95 | + </el-button> | |
| 94 | 96 | </template> |
| 95 | 97 | </el-table-column> |
| 96 | 98 | </el-table> |
| ... | ... | @@ -243,6 +245,10 @@ |
| 243 | 245 | }); |
| 244 | 246 | |
| 245 | 247 | }, |
| 248 | + queryCloudRecords: function (row) { | |
| 249 | + | |
| 250 | + this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`) | |
| 251 | + }, | |
| 246 | 252 | deleteStreamProxy: function(row){ |
| 247 | 253 | let that = this; |
| 248 | 254 | this.$confirm('确定删除此代理吗?', '提示', { | ... | ... |
web_src/src/components/UserManager.vue
100644 → 100755
web_src/src/components/channelList.vue
100644 → 100755
| ... | ... | @@ -105,6 +105,9 @@ |
| 105 | 105 | <el-divider v-if="scope.row.subCount > 0 || scope.row.parental === 1" direction="vertical"></el-divider> |
| 106 | 106 | <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-video-camera" type="text" @click="queryRecords(scope.row)">设备录像 |
| 107 | 107 | </el-button> |
| 108 | + <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-cloudy" | |
| 109 | + type="text" @click="queryCloudRecords(scope.row)">云端录像 | |
| 110 | + </el-button> | |
| 108 | 111 | </template> |
| 109 | 112 | </el-table-column> |
| 110 | 113 | </el-table> |
| ... | ... | @@ -283,6 +286,12 @@ export default { |
| 283 | 286 | |
| 284 | 287 | this.$router.push(`/gbRecordDetail/${deviceId}/${channelId}`) |
| 285 | 288 | }, |
| 289 | + queryCloudRecords: function (itemData) { | |
| 290 | + let deviceId = this.deviceId; | |
| 291 | + let channelId = itemData.channelId; | |
| 292 | + | |
| 293 | + this.$router.push(`/cloudRecordDetail/rtp/${deviceId}_${channelId}`) | |
| 294 | + }, | |
| 286 | 295 | stopDevicePush: function (itemData) { |
| 287 | 296 | var that = this; |
| 288 | 297 | this.$axios({ | ... | ... |
web_src/src/components/common/ h265web.vue
100644 → 100755
web_src/src/components/common/DeviceTree.vue
100644 → 100755
web_src/src/components/common/DeviceTreeForZtree.vue
100644 → 100755
web_src/src/components/common/MapComponent.vue
100644 → 100755
web_src/src/components/common/jessibuca.vue
100644 → 100755
web_src/src/components/console.vue
100644 → 100755
web_src/src/components/console/ConsoleCPU.vue
100644 → 100755
web_src/src/components/console/ConsoleDisk.vue
100644 → 100755
web_src/src/components/console/ConsoleMEM.vue
100644 → 100755
web_src/src/components/console/ConsoleMediaServer.vue
100644 → 100755
web_src/src/components/console/ConsoleNet.vue
100644 → 100755
web_src/src/components/console/ConsoleNodeLoad.vue
100644 → 100755
web_src/src/components/console/ConsoleResource.vue
100644 → 100755
web_src/src/components/dialog/MediaServerEdit.vue
100644 → 100755
web_src/src/components/dialog/StreamProxyEdit.vue
100644 → 100755
web_src/src/components/dialog/SyncChannelProgress.vue
100644 → 100755
web_src/src/components/dialog/catalogEdit.vue
100644 → 100755
web_src/src/components/dialog/changePassword.vue
100644 → 100755
web_src/src/components/dialog/changePasswordForAdmin.vue
100644 → 100755
web_src/src/components/dialog/changePushKey.vue
100644 → 100755
web_src/src/components/dialog/channelMapInfobox.vue
100644 → 100755
web_src/src/components/dialog/chooseChannel.vue
100644 → 100755
web_src/src/components/dialog/chooseChannelForCatalog.vue
100644 → 100755
web_src/src/components/dialog/chooseChannelForGb.vue
100644 → 100755
web_src/src/components/dialog/chooseChannelForStream.vue
100644 → 100755
web_src/src/components/dialog/configInfo.vue
100644 → 100755
web_src/src/components/dialog/deviceEdit.vue
100644 → 100755
web_src/src/components/dialog/devicePlayer.vue
100644 → 100755
web_src/src/components/dialog/easyPlayer.vue
100644 → 100755
web_src/src/components/dialog/getCatalog.vue
100644 → 100755
web_src/src/components/dialog/importChannel.vue
100644 → 100755
web_src/src/components/dialog/importChannelShowErrorData.vue
100644 → 100755
web_src/src/components/dialog/onvifEdit.vue
100644 → 100755
web_src/src/components/dialog/platformEdit.vue
100644 → 100755
web_src/src/components/dialog/pushStreamEdit.vue
100644 → 100755
web_src/src/components/dialog/queryTrace.vue
100644 → 100755
web_src/src/components/dialog/recordDownload.vue
100644 → 100755
web_src/src/components/dialog/rtcPlayer.vue
100644 → 100755
web_src/src/components/live.vue
100644 → 100755
web_src/src/components/map.vue
100644 → 100755
web_src/src/components/service/DeviceService.js
100644 → 100755
web_src/src/components/service/MediaServer.js
100644 → 100755
web_src/src/components/service/UserService.js
100644 → 100755
web_src/src/components/setting/Media.vue
100644 → 100755
web_src/src/components/setting/Sip.vue
100644 → 100755
web_src/src/components/setting/Web.vue
100644 → 100755
web_src/src/layout/UiHeader.vue
100644 → 100755
web_src/src/layout/index.vue
100644 → 100755
web_src/src/main.js
100644 → 100755
web_src/src/router/index.js
100644 → 100755
| ... | ... | @@ -12,6 +12,7 @@ import map from '../components/map.vue' |
| 12 | 12 | import login from '../components/Login.vue' |
| 13 | 13 | import parentPlatformList from '../components/ParentPlatformList.vue' |
| 14 | 14 | import cloudRecord from '../components/CloudRecord.vue' |
| 15 | +import cloudRecordDetail from '../components/CloudRecordDetail.vue' | |
| 15 | 16 | import mediaServerManger from '../components/MediaServerManger.vue' |
| 16 | 17 | import web from '../components/setting/Web.vue' |
| 17 | 18 | import sip from '../components/setting/Sip.vue' |
| ... | ... | @@ -86,6 +87,16 @@ export default new VueRouter({ |
| 86 | 87 | component: cloudRecord, |
| 87 | 88 | }, |
| 88 | 89 | { |
| 90 | + path: '/cloudRecordDetail/:app/:stream', | |
| 91 | + name: 'cloudRecordDetail', | |
| 92 | + component: cloudRecordDetail, | |
| 93 | + }, | |
| 94 | + { | |
| 95 | + path: '/cloudRecordDetail/:mediaServerId/:app/:stream', | |
| 96 | + name: 'cloudRecordDetail', | |
| 97 | + component: cloudRecordDetail, | |
| 98 | + }, | |
| 99 | + { | |
| 89 | 100 | path: '/mediaServerManger', |
| 90 | 101 | name: 'mediaServerManger', |
| 91 | 102 | component: mediaServerManger, | ... | ... |