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 | 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 | 7 | import java.util.Properties; |
| 4 | 8 | |
| 5 | 9 | /** |
| ... | ... | @@ -12,6 +16,7 @@ public class DefaultProperties { |
| 12 | 16 | Properties properties = new Properties(); |
| 13 | 17 | properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); |
| 14 | 18 | properties.setProperty("javax.sip.IP_ADDRESS", ip); |
| 19 | + // 关闭自动会话 | |
| 15 | 20 | properties.setProperty("javax.sip.AUTOMATIC_DIALOG_SUPPORT", "off"); |
| 16 | 21 | /** |
| 17 | 22 | * 完整配置参考 gov.nist.javax.sip.SipStackImpl,需要下载源码 |
| ... | ... | @@ -26,7 +31,7 @@ public class DefaultProperties { |
| 26 | 31 | // 接收所有notify请求,即使没有订阅 |
| 27 | 32 | properties.setProperty("gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY", "true"); |
| 28 | 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 | 35 | // 为_NULL _对话框传递_终止的_事件 |
| 31 | 36 | properties.setProperty("gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG", "true"); |
| 32 | 37 | // 会话清理策略 |
| ... | ... | @@ -35,11 +40,33 @@ public class DefaultProperties { |
| 35 | 40 | properties.setProperty("gov.nist.javax.sip.RELIABLE_CONNECTION_KEEP_ALIVE_TIMEOUT", "60"); |
| 36 | 41 | // 获取实际内容长度,不使用header中的长度信息 |
| 37 | 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 | 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 | 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 | 13 | import javax.sip.header.FromHeader; |
| 14 | 14 | import javax.sip.header.Header; |
| 15 | 15 | import javax.sip.header.UserAgentHeader; |
| 16 | -import javax.sip.header.ViaHeader; | |
| 17 | 16 | import javax.sip.message.Request; |
| 18 | 17 | import java.text.ParseException; |
| 19 | 18 | import java.util.ArrayList; |
| ... | ... | @@ -138,13 +137,12 @@ public class SipUtils { |
| 138 | 137 | }else { |
| 139 | 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 | 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 | 424 | logger.info("[ZLM HOOK]流无人观看:{]->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); |
| 425 | 425 | JSONObject ret = new JSONObject(); |
| 426 | 426 | ret.put("code", 0); |
| 427 | - // 录像下载 | |
| 427 | + // 国标类型的流 | |
| 428 | 428 | if ("rtp".equals(param.getApp())){ |
| 429 | 429 | ret.put("close", userSetting.getStreamOnDemand()); |
| 430 | 430 | // 国标流, 点播/录像回放/录像下载 |
| ... | ... | @@ -596,7 +596,7 @@ public class ZLMHttpHookListener { |
| 596 | 596 | @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8") |
| 597 | 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 | 601 | JSONObject ret = new JSONObject(); |
| 602 | 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 | 154 | } |
| 155 | 155 | // 刷新过期任务 |
| 156 | 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 | 161 | @Override | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
| ... | ... | @@ -135,14 +135,7 @@ public class PlatformServiceImpl implements IPlatformService { |
| 135 | 135 | dynamicTask.startCron(registerTaskKey, |
| 136 | 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 | 140 | (parentPlatform.getExpires() - 10) *1000); |
| 148 | 141 | } |
| ... | ... | @@ -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 | 212 | @Override |
| 198 | 213 | public void offline(ParentPlatform parentPlatform, boolean stopRegister) { |
| 199 | 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 | 106 | msg.setData(wvpResult); |
| 107 | 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 | 126 | // 录像查询以channelId作为deviceId查询 | ... | ... |
src/main/resources/all-application.yml
| ... | ... | @@ -186,7 +186,7 @@ user-settings: |
| 186 | 186 | use-pushing-as-status: true |
| 187 | 187 | # 使用来源请求ip作为streamIp,当且仅当你只有zlm节点它与wvp在一起的情况下开启 |
| 188 | 188 | use-source-ip-as-stream-ip: true |
| 189 | - # 按需拉流, true:有人观看拉流,无人观看释放, false:拉起后不自动释放 | |
| 189 | + # 国标点播 按需拉流, true:有人观看拉流,无人观看释放, false:拉起后不自动释放 | |
| 190 | 190 | stream-on-demand: true |
| 191 | 191 | # 推流鉴权, 默认开启 |
| 192 | 192 | push-authority: true |
| ... | ... | @@ -195,8 +195,8 @@ user-settings: |
| 195 | 195 | gb-send-stream-strict: false |
| 196 | 196 | # 设备上线时是否自动同步通道 |
| 197 | 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 | 202 | springdoc: | ... | ... |