Commit c1145a816399528e81589eef11046d877315ad5e
1 parent
15169913
优化级联注册,以及sip日志
Showing
8 changed files
with
77 additions
and
146 deletions
src/main/java/com/genersoft/iot/vmp/gb28181/conf/DefaultProperties.java
| 1 | package com.genersoft.iot.vmp.gb28181.conf; | 1 | package com.genersoft.iot.vmp.gb28181.conf; |
| 2 | 2 | ||
| 3 | +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd.AlarmNotifyMessageHandler; | ||
| 4 | +import org.slf4j.Logger; | ||
| 5 | +import org.slf4j.LoggerFactory; | ||
| 6 | + | ||
| 3 | import java.util.Properties; | 7 | import java.util.Properties; |
| 4 | 8 | ||
| 5 | /** | 9 | /** |
| @@ -12,6 +16,7 @@ public class DefaultProperties { | @@ -12,6 +16,7 @@ public class DefaultProperties { | ||
| 12 | Properties properties = new Properties(); | 16 | Properties properties = new Properties(); |
| 13 | properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); | 17 | properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); |
| 14 | properties.setProperty("javax.sip.IP_ADDRESS", ip); | 18 | properties.setProperty("javax.sip.IP_ADDRESS", ip); |
| 19 | + // 关闭自动会话 | ||
| 15 | properties.setProperty("javax.sip.AUTOMATIC_DIALOG_SUPPORT", "off"); | 20 | properties.setProperty("javax.sip.AUTOMATIC_DIALOG_SUPPORT", "off"); |
| 16 | /** | 21 | /** |
| 17 | * 完整配置参考 gov.nist.javax.sip.SipStackImpl,需要下载源码 | 22 | * 完整配置参考 gov.nist.javax.sip.SipStackImpl,需要下载源码 |
| @@ -26,7 +31,7 @@ public class DefaultProperties { | @@ -26,7 +31,7 @@ public class DefaultProperties { | ||
| 26 | // 接收所有notify请求,即使没有订阅 | 31 | // 接收所有notify请求,即使没有订阅 |
| 27 | properties.setProperty("gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY", "true"); | 32 | properties.setProperty("gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY", "true"); |
| 28 | properties.setProperty("gov.nist.javax.sip.AUTOMATIC_DIALOG_ERROR_HANDLING", "false"); | 33 | properties.setProperty("gov.nist.javax.sip.AUTOMATIC_DIALOG_ERROR_HANDLING", "false"); |
| 29 | - properties.setProperty("gov.nist.javax.sip.CANCEL_CLIENT_TRANSACTION_CHECKED", "false"); | 34 | + properties.setProperty("gov.nist.javax.sip.CANCEL_CLIENT_TRANSACTION_CHECKED", "true"); |
| 30 | // 为_NULL _对话框传递_终止的_事件 | 35 | // 为_NULL _对话框传递_终止的_事件 |
| 31 | properties.setProperty("gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG", "true"); | 36 | properties.setProperty("gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG", "true"); |
| 32 | // 会话清理策略 | 37 | // 会话清理策略 |
| @@ -35,11 +40,33 @@ public class DefaultProperties { | @@ -35,11 +40,33 @@ public class DefaultProperties { | ||
| 35 | properties.setProperty("gov.nist.javax.sip.RELIABLE_CONNECTION_KEEP_ALIVE_TIMEOUT", "60"); | 40 | properties.setProperty("gov.nist.javax.sip.RELIABLE_CONNECTION_KEEP_ALIVE_TIMEOUT", "60"); |
| 36 | // 获取实际内容长度,不使用header中的长度信息 | 41 | // 获取实际内容长度,不使用header中的长度信息 |
| 37 | properties.setProperty("gov.nist.javax.sip.COMPUTE_CONTENT_LENGTH_FROM_MESSAGE_BODY", "true"); | 42 | properties.setProperty("gov.nist.javax.sip.COMPUTE_CONTENT_LENGTH_FROM_MESSAGE_BODY", "true"); |
| 43 | + // 线程可重入 | ||
| 44 | + properties.setProperty("gov.nist.javax.sip.REENTRANT_LISTENER", "true"); | ||
| 45 | + // 定义应用程序打算多久审计一次 SIP 堆栈,了解其内部线程的健康状况(该属性指定连续审计之间的时间(以毫秒为单位)) | ||
| 46 | + properties.setProperty("gov.nist.javax.sip.THREAD_AUDIT_INTERVAL_IN_MILLISECS", "30000"); | ||
| 38 | 47 | ||
| 39 | /** | 48 | /** |
| 40 | * sip_server_log.log 和 sip_debug_log.log ERROR, INFO, WARNING, OFF, DEBUG, TRACE | 49 | * sip_server_log.log 和 sip_debug_log.log ERROR, INFO, WARNING, OFF, DEBUG, TRACE |
| 41 | */ | 50 | */ |
| 42 | - properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "ERROR"); | 51 | + Logger logger = LoggerFactory.getLogger(AlarmNotifyMessageHandler.class); |
| 52 | + if (logger.isDebugEnabled()) { | ||
| 53 | + System.out.println("DEBUG"); | ||
| 54 | + properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "DEBUG"); | ||
| 55 | + }else if (logger.isInfoEnabled()) { | ||
| 56 | + System.out.println("INFO1"); | ||
| 57 | + properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "INFO"); | ||
| 58 | + }else if (logger.isWarnEnabled()) { | ||
| 59 | + System.out.println("WARNING"); | ||
| 60 | + properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "WARNING"); | ||
| 61 | + }else if (logger.isErrorEnabled()) { | ||
| 62 | + System.out.println("ERROR"); | ||
| 63 | + properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "ERROR"); | ||
| 64 | + }else { | ||
| 65 | + System.out.println("INFO2"); | ||
| 66 | + properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "INFO"); | ||
| 67 | + } | ||
| 68 | + logger.info("[SIP日志]级别为: {}", properties.getProperty("gov.nist.javax.sip.TRACE_LEVEL")); | ||
| 69 | + | ||
| 43 | 70 | ||
| 44 | return properties; | 71 | return properties; |
| 45 | } | 72 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/conf/SipLoggerPass.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.gb28181.conf; | ||
| 2 | - | ||
| 3 | -import gov.nist.core.StackLogger; | ||
| 4 | - | ||
| 5 | -import java.util.Properties; | ||
| 6 | - | ||
| 7 | -/** | ||
| 8 | - * sip日志格式化 | ||
| 9 | - * 暂不使用 | ||
| 10 | - */ | ||
| 11 | -public class SipLoggerPass implements StackLogger { | ||
| 12 | - | ||
| 13 | - @Override | ||
| 14 | - public void logStackTrace() { | ||
| 15 | - | ||
| 16 | - } | ||
| 17 | - | ||
| 18 | - @Override | ||
| 19 | - public void logStackTrace(int traceLevel) { | ||
| 20 | - | ||
| 21 | - } | ||
| 22 | - | ||
| 23 | - @Override | ||
| 24 | - public int getLineCount() { | ||
| 25 | - return 0; | ||
| 26 | - } | ||
| 27 | - | ||
| 28 | - @Override | ||
| 29 | - public void logException(Throwable ex) { | ||
| 30 | - | ||
| 31 | - } | ||
| 32 | - | ||
| 33 | - @Override | ||
| 34 | - public void logDebug(String message) { | ||
| 35 | - | ||
| 36 | - } | ||
| 37 | - | ||
| 38 | - @Override | ||
| 39 | - public void logDebug(String message, Exception ex) { | ||
| 40 | - | ||
| 41 | - } | ||
| 42 | - | ||
| 43 | - @Override | ||
| 44 | - public void logTrace(String message) { | ||
| 45 | - | ||
| 46 | - } | ||
| 47 | - | ||
| 48 | - @Override | ||
| 49 | - public void logFatalError(String message) { | ||
| 50 | - | ||
| 51 | - } | ||
| 52 | - | ||
| 53 | - @Override | ||
| 54 | - public void logError(String message) { | ||
| 55 | - | ||
| 56 | - } | ||
| 57 | - | ||
| 58 | - @Override | ||
| 59 | - public boolean isLoggingEnabled() { | ||
| 60 | - return false; | ||
| 61 | - } | ||
| 62 | - | ||
| 63 | - @Override | ||
| 64 | - public boolean isLoggingEnabled(int logLevel) { | ||
| 65 | - return false; | ||
| 66 | - } | ||
| 67 | - | ||
| 68 | - @Override | ||
| 69 | - public void logError(String message, Exception ex) { | ||
| 70 | - | ||
| 71 | - } | ||
| 72 | - | ||
| 73 | - @Override | ||
| 74 | - public void logWarning(String string) { | ||
| 75 | - | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - @Override | ||
| 79 | - public void logInfo(String string) { | ||
| 80 | - | ||
| 81 | - } | ||
| 82 | - | ||
| 83 | - @Override | ||
| 84 | - public void disableLogging() { | ||
| 85 | - | ||
| 86 | - } | ||
| 87 | - | ||
| 88 | - @Override | ||
| 89 | - public void enableLogging() { | ||
| 90 | - | ||
| 91 | - } | ||
| 92 | - | ||
| 93 | - @Override | ||
| 94 | - public void setBuildTimeStamp(String buildTimeStamp) { | ||
| 95 | - | ||
| 96 | - } | ||
| 97 | - | ||
| 98 | - @Override | ||
| 99 | - public void setStackProperties(Properties stackProperties) { | ||
| 100 | - | ||
| 101 | - } | ||
| 102 | - | ||
| 103 | - @Override | ||
| 104 | - public String getLoggerName() { | ||
| 105 | - return null; | ||
| 106 | - } | ||
| 107 | -} |
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
| @@ -13,7 +13,6 @@ import javax.sip.SipFactory; | @@ -13,7 +13,6 @@ import javax.sip.SipFactory; | ||
| 13 | import javax.sip.header.FromHeader; | 13 | import javax.sip.header.FromHeader; |
| 14 | import javax.sip.header.Header; | 14 | import javax.sip.header.Header; |
| 15 | import javax.sip.header.UserAgentHeader; | 15 | import javax.sip.header.UserAgentHeader; |
| 16 | -import javax.sip.header.ViaHeader; | ||
| 17 | import javax.sip.message.Request; | 16 | import javax.sip.message.Request; |
| 18 | import java.text.ParseException; | 17 | import java.text.ParseException; |
| 19 | import java.util.ArrayList; | 18 | import java.util.ArrayList; |
| @@ -138,13 +137,12 @@ public class SipUtils { | @@ -138,13 +137,12 @@ public class SipUtils { | ||
| 138 | }else { | 137 | }else { |
| 139 | // 判断RPort是否改变,改变则说明路由nat信息变化,修改设备信息 | 138 | // 判断RPort是否改变,改变则说明路由nat信息变化,修改设备信息 |
| 140 | // 获取到通信地址等信息 | 139 | // 获取到通信地址等信息 |
| 141 | - ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); | ||
| 142 | - remoteAddress = viaHeader.getReceived(); | ||
| 143 | - remotePort = viaHeader.getRPort(); | 140 | + remoteAddress = request.getTopmostViaHeader().getReceived(); |
| 141 | + remotePort = request.getTopmostViaHeader().getRPort(); | ||
| 144 | // 解析本地地址替代 | 142 | // 解析本地地址替代 |
| 145 | if (ObjectUtils.isEmpty(remoteAddress) || remotePort == -1) { | 143 | if (ObjectUtils.isEmpty(remoteAddress) || remotePort == -1) { |
| 146 | - remoteAddress = viaHeader.getHost(); | ||
| 147 | - remotePort = viaHeader.getPort(); | 144 | + remoteAddress = request.getTopmostViaHeader().getHost(); |
| 145 | + remotePort = request.getTopmostViaHeader().getPort(); | ||
| 148 | } | 146 | } |
| 149 | } | 147 | } |
| 150 | 148 |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| @@ -424,7 +424,7 @@ public class ZLMHttpHookListener { | @@ -424,7 +424,7 @@ public class ZLMHttpHookListener { | ||
| 424 | logger.info("[ZLM HOOK]流无人观看:{]->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); | 424 | logger.info("[ZLM HOOK]流无人观看:{]->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); |
| 425 | JSONObject ret = new JSONObject(); | 425 | JSONObject ret = new JSONObject(); |
| 426 | ret.put("code", 0); | 426 | ret.put("code", 0); |
| 427 | - // 录像下载 | 427 | + // 国标类型的流 |
| 428 | if ("rtp".equals(param.getApp())){ | 428 | if ("rtp".equals(param.getApp())){ |
| 429 | ret.put("close", userSetting.getStreamOnDemand()); | 429 | ret.put("close", userSetting.getStreamOnDemand()); |
| 430 | // 国标流, 点播/录像回放/录像下载 | 430 | // 国标流, 点播/录像回放/录像下载 |
| @@ -596,7 +596,7 @@ public class ZLMHttpHookListener { | @@ -596,7 +596,7 @@ public class ZLMHttpHookListener { | ||
| 596 | @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8") | 596 | @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8") |
| 597 | public JSONObject onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param){ | 597 | public JSONObject onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param){ |
| 598 | 598 | ||
| 599 | - logger.info("[ZLM HOOK] 发送rtp被动关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream()); | 599 | + logger.info("[ZLM HOOK] rtp发送关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream()); |
| 600 | 600 | ||
| 601 | JSONObject ret = new JSONObject(); | 601 | JSONObject ret = new JSONObject(); |
| 602 | ret.put("code", 0); | 602 | ret.put("code", 0); |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
| @@ -154,7 +154,8 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -154,7 +154,8 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 154 | } | 154 | } |
| 155 | // 刷新过期任务 | 155 | // 刷新过期任务 |
| 156 | String registerExpireTaskKey = registerExpireTaskKeyPrefix + device.getDeviceId(); | 156 | String registerExpireTaskKey = registerExpireTaskKeyPrefix + device.getDeviceId(); |
| 157 | - dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId()), device.getExpires() * 1000); | 157 | + // 增加一个10秒给设备重发消息的机会 |
| 158 | + dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId()), (device.getExpires() + 10) * 1000); | ||
| 158 | } | 159 | } |
| 159 | 160 | ||
| 160 | @Override | 161 | @Override |
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
| @@ -135,14 +135,7 @@ public class PlatformServiceImpl implements IPlatformService { | @@ -135,14 +135,7 @@ public class PlatformServiceImpl implements IPlatformService { | ||
| 135 | dynamicTask.startCron(registerTaskKey, | 135 | dynamicTask.startCron(registerTaskKey, |
| 136 | // 注册失败(注册成功时由程序直接调用了online方法) | 136 | // 注册失败(注册成功时由程序直接调用了online方法) |
| 137 | ()-> { | 137 | ()-> { |
| 138 | - try { | ||
| 139 | - logger.info("[国标级联] 平台:{}注册即将到期,重新注册", parentPlatform.getServerGBId()); | ||
| 140 | - commanderForPlatform.register(parentPlatform, eventResult -> { | ||
| 141 | - offline(parentPlatform, false); | ||
| 142 | - },null); | ||
| 143 | - } catch (InvalidArgumentException | ParseException | SipException e) { | ||
| 144 | - logger.error("[命令发送失败] 国标级联定时注册: {}", e.getMessage()); | ||
| 145 | - } | 138 | + registerTask(parentPlatform); |
| 146 | }, | 139 | }, |
| 147 | (parentPlatform.getExpires() - 10) *1000); | 140 | (parentPlatform.getExpires() - 10) *1000); |
| 148 | } | 141 | } |
| @@ -194,6 +187,28 @@ public class PlatformServiceImpl implements IPlatformService { | @@ -194,6 +187,28 @@ public class PlatformServiceImpl implements IPlatformService { | ||
| 194 | } | 187 | } |
| 195 | } | 188 | } |
| 196 | 189 | ||
| 190 | + private void registerTask(ParentPlatform parentPlatform){ | ||
| 191 | + try { | ||
| 192 | + // 设置超时重发, 后续从底层支持消息重发 | ||
| 193 | + String key = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId() + "_timeout"; | ||
| 194 | + if (dynamicTask.isAlive(key)) { | ||
| 195 | + return; | ||
| 196 | + } | ||
| 197 | + dynamicTask.startDelay(key, ()->{ | ||
| 198 | + registerTask(parentPlatform); | ||
| 199 | + }, 1000); | ||
| 200 | + logger.info("[国标级联] 平台:{}注册即将到期,重新注册", parentPlatform.getServerGBId()); | ||
| 201 | + commanderForPlatform.register(parentPlatform, eventResult -> { | ||
| 202 | + dynamicTask.stop(key); | ||
| 203 | + offline(parentPlatform, false); | ||
| 204 | + },eventResult -> { | ||
| 205 | + dynamicTask.stop(key); | ||
| 206 | + }); | ||
| 207 | + } catch (InvalidArgumentException | ParseException | SipException e) { | ||
| 208 | + logger.error("[命令发送失败] 国标级联定时注册: {}", e.getMessage()); | ||
| 209 | + } | ||
| 210 | + } | ||
| 211 | + | ||
| 197 | @Override | 212 | @Override |
| 198 | public void offline(ParentPlatform parentPlatform, boolean stopRegister) { | 213 | public void offline(ParentPlatform parentPlatform, boolean stopRegister) { |
| 199 | logger.info("[平台离线]:{}", parentPlatform.getServerGBId()); | 214 | logger.info("[平台离线]:{}", parentPlatform.getServerGBId()); |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
| @@ -106,24 +106,21 @@ public class PlayController { | @@ -106,24 +106,21 @@ public class PlayController { | ||
| 106 | msg.setData(wvpResult); | 106 | msg.setData(wvpResult); |
| 107 | resultHolder.invokeResult(msg); | 107 | resultHolder.invokeResult(msg); |
| 108 | }); | 108 | }); |
| 109 | - | ||
| 110 | - | ||
| 111 | - // TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误 | ||
| 112 | - deferredResultEx.setFilter(result1 -> { | ||
| 113 | - WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>)result1; | ||
| 114 | - WVPResult<StreamContent> resultStream = null; | ||
| 115 | - if (wvpResult1.getCode() == ErrorCode.SUCCESS.getCode()) { | ||
| 116 | - StreamInfo data = wvpResult1.getData().clone(); | ||
| 117 | - if (userSetting.getUseSourceIpAsStreamIp()) { | ||
| 118 | - data.channgeStreamIp(request.getLocalName()); | ||
| 119 | - } | ||
| 120 | - resultStream = new WVPResult<>(); | ||
| 121 | - resultStream.setCode(wvpResult1.getCode()); | ||
| 122 | - resultStream.setMsg(wvpResult1.getMsg()); | ||
| 123 | - resultStream.setData(new StreamContent(wvpResult1.getData())); | 109 | + // TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误 |
| 110 | + deferredResultEx.setFilter(result1 -> { | ||
| 111 | + WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>)result1; | ||
| 112 | + WVPResult<StreamContent> resultStream = new WVPResult<>(); | ||
| 113 | + resultStream.setCode(wvpResult1.getCode()); | ||
| 114 | + resultStream.setMsg(wvpResult1.getMsg()); | ||
| 115 | + if (wvpResult1.getCode() == ErrorCode.SUCCESS.getCode()) { | ||
| 116 | + StreamInfo data = wvpResult1.getData().clone(); | ||
| 117 | + if (userSetting.getUseSourceIpAsStreamIp()) { | ||
| 118 | + data.channgeStreamIp(request.getLocalName()); | ||
| 124 | } | 119 | } |
| 125 | - return resultStream; | ||
| 126 | - }); | 120 | + resultStream.setData(new StreamContent(wvpResult1.getData())); |
| 121 | + } | ||
| 122 | + return resultStream; | ||
| 123 | + }); | ||
| 127 | 124 | ||
| 128 | 125 | ||
| 129 | // 录像查询以channelId作为deviceId查询 | 126 | // 录像查询以channelId作为deviceId查询 |
src/main/resources/all-application.yml
| @@ -186,7 +186,7 @@ user-settings: | @@ -186,7 +186,7 @@ user-settings: | ||
| 186 | use-pushing-as-status: true | 186 | use-pushing-as-status: true |
| 187 | # 使用来源请求ip作为streamIp,当且仅当你只有zlm节点它与wvp在一起的情况下开启 | 187 | # 使用来源请求ip作为streamIp,当且仅当你只有zlm节点它与wvp在一起的情况下开启 |
| 188 | use-source-ip-as-stream-ip: true | 188 | use-source-ip-as-stream-ip: true |
| 189 | - # 按需拉流, true:有人观看拉流,无人观看释放, false:拉起后不自动释放 | 189 | + # 国标点播 按需拉流, true:有人观看拉流,无人观看释放, false:拉起后不自动释放 |
| 190 | stream-on-demand: true | 190 | stream-on-demand: true |
| 191 | # 推流鉴权, 默认开启 | 191 | # 推流鉴权, 默认开启 |
| 192 | push-authority: true | 192 | push-authority: true |
| @@ -195,8 +195,8 @@ user-settings: | @@ -195,8 +195,8 @@ user-settings: | ||
| 195 | gb-send-stream-strict: false | 195 | gb-send-stream-strict: false |
| 196 | # 设备上线时是否自动同步通道 | 196 | # 设备上线时是否自动同步通道 |
| 197 | sync-channel-on-device-online: false | 197 | sync-channel-on-device-online: false |
| 198 | - # 设备上线时是否自动同步通道 | ||
| 199 | - sip-use-source-ip-as-remote-address: true | 198 | + # 是否使用设备来源Ip作为回复IP, 不设置则为 false |
| 199 | + sip-use-source-ip-as-remote-address: false | ||
| 200 | 200 | ||
| 201 | # 关闭在线文档(生产环境建议关闭) | 201 | # 关闭在线文档(生产环境建议关闭) |
| 202 | springdoc: | 202 | springdoc: |