sip 监听创建/销毁
支持 hotReload
This commit is contained in:
parent
5483effad4
commit
f2c78c4b78
12
api/pom.xml
12
api/pom.xml
@ -18,4 +18,16 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>${springdoc.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-common</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -80,6 +80,11 @@
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -0,0 +1,56 @@
|
||||
package cn.skcks.docking.gb28181.common.json;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@SuppressWarnings("unused")
|
||||
@Schema(title = "返回结果")
|
||||
public class JsonResponse<T> {
|
||||
@Schema(title = "状态码")
|
||||
private int code;
|
||||
|
||||
@Schema(title = "响应消息")
|
||||
private String msg;
|
||||
|
||||
@Schema(title = "响应数据")
|
||||
private T data;
|
||||
|
||||
public JsonResponse(int code, String msg, T data) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public static <T> JsonResponse<T> success(T data) {
|
||||
return JsonResponse.build(data, ResponseStatus.OK);
|
||||
}
|
||||
|
||||
public static <T> JsonResponse<T> success(T data, String message) {
|
||||
return JsonResponse.build(data, ResponseStatus.OK.getCode(), message);
|
||||
}
|
||||
|
||||
public static <T> JsonResponse<T> error(T data) {
|
||||
return JsonResponse.build(data, ResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
public static <T> JsonResponse<T> error(T data, String message) {
|
||||
return JsonResponse.build(data, ResponseStatus.INTERNAL_SERVER_ERROR.getCode(), message);
|
||||
}
|
||||
|
||||
public static <T> JsonResponse<T> build(ResponseStatus status) {
|
||||
return new JsonResponse<>(status.getCode(), status.getMessage(),null);
|
||||
}
|
||||
|
||||
public static <T> JsonResponse<T> build(T data, ResponseStatus status) {
|
||||
return new JsonResponse<>(status.getCode(), status.getMessage(), data);
|
||||
}
|
||||
|
||||
public static <T> JsonResponse<T> build(ResponseStatus status,String message) {
|
||||
return new JsonResponse<>(status.getCode(), message, null);
|
||||
}
|
||||
|
||||
public static <T> JsonResponse<T> build(T data, int status, String msg) {
|
||||
return new JsonResponse<>(status, msg, data);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package cn.skcks.docking.gb28181.common.json;
|
||||
|
||||
import com.fasterxml.jackson.core.json.JsonReadFeature;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class JsonUtils {
|
||||
public static final ObjectMapper mapper;
|
||||
public static final ObjectMapper compressMapper;
|
||||
|
||||
static {
|
||||
mapper = new ObjectMapper();
|
||||
compressMapper = new ObjectMapper();
|
||||
|
||||
mapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
compressMapper.disable(SerializationFeature.INDENT_OUTPUT);
|
||||
|
||||
// 返回内容中 不含 值为 null 的字段
|
||||
// mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
compressMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
|
||||
// 如果json中有新增的字段并且是实体类类中不存在的,不报错
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
|
||||
|
||||
compressMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
compressMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
|
||||
|
||||
// 允许出现特殊字符和转义符
|
||||
mapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
|
||||
compressMapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
|
||||
|
||||
// 允许出现单引号
|
||||
mapper.configure(JsonReadFeature.ALLOW_SINGLE_QUOTES.mappedFeature(), true);
|
||||
compressMapper.configure(JsonReadFeature.ALLOW_SINGLE_QUOTES.mappedFeature(), true);
|
||||
}
|
||||
|
||||
public static <T> T parse(String json, Class<T> clazz) {
|
||||
try {
|
||||
return mapper.readValue(json, clazz);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T parse(String json, TypeReference<T> clazz) {
|
||||
try {
|
||||
return mapper.readValue(json, clazz);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String toCompressJson(Object obj) {
|
||||
try {
|
||||
return compressMapper.writeValueAsString(obj);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String toJson(Object obj) {
|
||||
try {
|
||||
return mapper.writeValueAsString(obj);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T convert(Object object, Class<T> clazz) {
|
||||
return JsonUtils.parse(JsonUtils.toJson(object), clazz);
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package cn.skcks.docking.gb28181.common.json;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@SuppressWarnings("unused")
|
||||
public enum ResponseStatus {
|
||||
UNKNOWN(-1, "Unknown"),
|
||||
UNDEFINED(0, "Undefined"),
|
||||
OK(200, "OK"),
|
||||
CREATED(201, "Created"),
|
||||
ACCEPTED(202, "Accepted"),
|
||||
NO_CONTENT(204, "No Content"),
|
||||
MOVED_PERMANENTLY(301, "Moved Permanently"),
|
||||
FOUND(302, "Found"),
|
||||
SEE_OTHER(303, "See Other"),
|
||||
NOT_MODIFIED(304, "Not Modified"),
|
||||
TEMPORARY_REDIRECT(307, "Temporary Redirect"),
|
||||
BAD_REQUEST(400, "Bad Request"),
|
||||
UNAUTHORIZED(401, "Unauthorized"),
|
||||
FORBIDDEN(403, "Forbidden"),
|
||||
NOT_FOUND(404, "Not Found"),
|
||||
METHOD_NOT_ALLOWED(405, "Method Not Allowed"),
|
||||
NOT_ACCEPTABLE(406, "Not Acceptable"),
|
||||
REQUEST_TIMEOUT(408, "Request Timeout"),
|
||||
CONFLICT(409, "Conflict"),
|
||||
GONE(410, "Gone"),
|
||||
LENGTH_REQUIRED(411, "Length Required"),
|
||||
PRECONDITION_FAILED(412, "Precondition Failed"),
|
||||
PAYLOAD_TOO_LARGE(413, "Payload Too Large"),
|
||||
URI_TOO_LONG(414, "URI Too Long"),
|
||||
UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"),
|
||||
RANGE_NOT_SATISFIABLE(416, "Range Not Satisfiable"),
|
||||
EXPECTATION_FAILED(417, "Expectation Failed"),
|
||||
TOO_MANY_REQUESTS(429, "Too Many Requests"),
|
||||
INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
|
||||
NOT_IMPLEMENTED(501, "Not Implemented"),
|
||||
BAD_GATEWAY(502, "Bad Gateway"),
|
||||
SERVICE_UNAVAILABLE(503, "Service Unavailable");
|
||||
|
||||
|
||||
private final int code;
|
||||
private final String message;
|
||||
|
||||
public static ResponseStatus getByCode(int code) {
|
||||
for (ResponseStatus status : values()) {
|
||||
if (status.getCode() == code) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ResponseStatus valueOf(int code) {
|
||||
return getByCode(code);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,17 @@
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.skcks.docking.gb28181</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- sip协议栈 -->
|
||||
<dependency>
|
||||
<groupId>javax.sip</groupId>
|
||||
|
@ -0,0 +1,42 @@
|
||||
package cn.skcks.docking.gb28181.config.sip;
|
||||
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "gb28181.sip", ignoreInvalidFields = true)
|
||||
@Order(0)
|
||||
@Data
|
||||
public class SipConfig {
|
||||
|
||||
private List<String> ip;
|
||||
|
||||
private List<String> showIp;
|
||||
|
||||
private Integer port;
|
||||
|
||||
private String domain;
|
||||
|
||||
private String id;
|
||||
|
||||
private String password;
|
||||
|
||||
Integer ptzSpeed = 50;
|
||||
|
||||
Integer registerTimeInterval = 120;
|
||||
|
||||
private boolean alarm;
|
||||
|
||||
public List<String> getShowIp() {
|
||||
if (this.showIp == null) {
|
||||
return this.ip;
|
||||
}
|
||||
return showIp;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package cn.skcks.docking.gb28181.core.sip;
|
||||
|
||||
public interface SipService {
|
||||
void run();
|
||||
void stop();
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package cn.skcks.docking.gb28181.core.sip;
|
||||
|
||||
import cn.skcks.docking.gb28181.config.sip.SipConfig;
|
||||
import cn.skcks.docking.gb28181.core.sip.properties.DefaultProperties;
|
||||
import gov.nist.javax.sip.SipProviderImpl;
|
||||
import gov.nist.javax.sip.SipStackImpl;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.sip.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.TooManyListenersException;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Data
|
||||
@Service
|
||||
public class SipServiceImpl implements SipService{
|
||||
private final SipFactory sipFactory = SipFactory.getInstance();
|
||||
private final SipConfig sipConfig;
|
||||
private final List<SipProviderImpl> pool = new ArrayList<>(2);
|
||||
private SipStackImpl sipStack;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
sipFactory.setPathName("gov.nist");
|
||||
sipConfig.getIp().parallelStream().forEach(ip->{
|
||||
listen(ip, sipConfig.getPort());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if(sipStack == null){
|
||||
return;
|
||||
}
|
||||
|
||||
sipStack.closeAllSockets();
|
||||
pool.parallelStream().forEach(sipProvider -> {
|
||||
ListeningPoint listen = sipProvider.getListeningPoint();
|
||||
log.debug("移除监听 {}://{}:{}",listen.getTransport(),listen.getIPAddress(),listen.getPort());
|
||||
sipProvider.removeListeningPoints();
|
||||
|
||||
try{
|
||||
sipStack.deleteListeningPoint(listen);
|
||||
sipStack.deleteSipProvider(sipProvider);
|
||||
} catch (Exception ignore){
|
||||
}
|
||||
});
|
||||
pool.clear();
|
||||
}
|
||||
|
||||
public void listen(String ip, int port){
|
||||
try{
|
||||
sipStack = (SipStackImpl)sipFactory.createSipStack(DefaultProperties.getProperties("GB28181_SIP_LOG",true));
|
||||
|
||||
try {
|
||||
ListeningPoint tcpListen = sipStack.createListeningPoint(ip, port, "TCP");
|
||||
SipProviderImpl tcpSipProvider = (SipProviderImpl) sipStack.createSipProvider(tcpListen);
|
||||
tcpSipProvider.setDialogErrorsAutomaticallyHandled();
|
||||
pool.add(tcpSipProvider);
|
||||
log.info("[sip] 监听 tcp://{}:{}", ip, port);
|
||||
} catch (TransportNotSupportedException
|
||||
| ObjectInUseException
|
||||
| InvalidArgumentException e) {
|
||||
log.error("[sip] tcp://{}:{} 监听失败, 请检查端口是否被占用, 错误信息 => {}", ip, port, e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
ListeningPoint udpListen = sipStack.createListeningPoint(ip, port, "UDP");
|
||||
SipProviderImpl udpSipProvider = (SipProviderImpl) sipStack.createSipProvider(udpListen);
|
||||
pool.add(udpSipProvider);
|
||||
log.info("[sip] 监听 udp://{}:{}", ip, port);
|
||||
} catch (TransportNotSupportedException
|
||||
| ObjectInUseException
|
||||
| InvalidArgumentException e) {
|
||||
log.error("[sip] udp://{}:{} 监听失败, 请检查端口是否被占用, 错误信息 => {}", ip, port, e.getMessage());
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("[sip] {}:{} 监听失败, 请检查端口是否被占用, 错误信息 => {}",ip,port, e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package cn.skcks.docking.gb28181.core.sip.logger;
|
||||
|
||||
import gov.nist.core.CommonLogger;
|
||||
import gov.nist.core.ServerLogger;
|
||||
import gov.nist.core.StackLogger;
|
||||
import gov.nist.javax.sip.message.SIPMessage;
|
||||
import gov.nist.javax.sip.stack.SIPTransactionStack;
|
||||
|
||||
import javax.sip.SipStack;
|
||||
import java.util.Properties;
|
||||
|
||||
public class ServerLoggerImpl implements ServerLogger {
|
||||
|
||||
private boolean showLog = true;
|
||||
|
||||
protected StackLogger stackLogger;
|
||||
|
||||
@Override
|
||||
public void closeLogFile() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logMessage(SIPMessage message, String from, String to, boolean sender, long time) {
|
||||
if (!showLog) {
|
||||
return;
|
||||
}
|
||||
String log = (sender ? "发送: 目标 =>" + from : "接收: 来自 =>" + to) + "\r\n" + message;
|
||||
this.stackLogger.logInfo(log);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logMessage(SIPMessage message, String from, String to, String status, boolean sender, long time) {
|
||||
if (!showLog) {
|
||||
return;
|
||||
}
|
||||
String log = (sender ? "发送: 目标 =>" + from : "接收: 来自 =>" + to) + "\r\n" + message;
|
||||
this.stackLogger.logInfo(log);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logMessage(SIPMessage message, String from, String to, String status, boolean sender) {
|
||||
if (!showLog) {
|
||||
return;
|
||||
}
|
||||
String log = (sender ? "发送: 目标 =>" + from : "接收: 来自 =>" + to) + "\r\n" + message;
|
||||
this.stackLogger.logInfo(log);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logException(Exception ex) {
|
||||
if (!showLog) {
|
||||
return;
|
||||
}
|
||||
this.stackLogger.logException(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStackProperties(Properties stackProperties) {
|
||||
if (!showLog) {
|
||||
return;
|
||||
}
|
||||
String TRACE_LEVEL = stackProperties.getProperty("gov.nist.javax.sip.TRACE_LEVEL");
|
||||
if (TRACE_LEVEL != null) {
|
||||
showLog = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSipStack(SipStack sipStack) {
|
||||
if (!showLog) {
|
||||
return;
|
||||
}
|
||||
if(sipStack instanceof SIPTransactionStack) {
|
||||
SIPTransactionStack sipStack1 = (SIPTransactionStack) sipStack;
|
||||
this.stackLogger = CommonLogger.getLogger(SIPTransactionStack.class);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package cn.skcks.docking.gb28181.core.sip.logger;
|
||||
|
||||
import gov.nist.core.StackLogger;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class StackLoggerImpl implements StackLogger {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(StackLoggerImpl.class);
|
||||
|
||||
@Override
|
||||
public void logStackTrace() {}
|
||||
|
||||
@Override
|
||||
public void logStackTrace(int traceLevel) {
|
||||
System.out.println("traceLevel: " + traceLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLineCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logException(Throwable ex) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logDebug(String message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logDebug(String message, Exception ex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logTrace(String message) {
|
||||
logger.trace(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logFatalError(String message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logError(String message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoggingEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoggingEnabled(int logLevel) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logError(String message, Exception ex) {
|
||||
// logger.error(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logWarning(String message) {
|
||||
logger.warn(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logInfo(String message) {
|
||||
logger.info(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableLogging() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableLogging() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBuildTimeStamp(String buildTimeStamp) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStackProperties(Properties stackProperties) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoggerName() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package cn.skcks.docking.gb28181.core.sip.properties;
|
||||
|
||||
import cn.skcks.docking.gb28181.config.sip.SipConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 获取sip默认配置
|
||||
*/
|
||||
public class DefaultProperties {
|
||||
|
||||
public static Properties getProperties(String name, boolean sipLog) {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("javax.sip.STACK_NAME", name);
|
||||
// properties.setProperty("javax.sip.IP_ADDRESS", ip);
|
||||
// 关闭自动会话
|
||||
properties.setProperty("javax.sip.AUTOMATIC_DIALOG_SUPPORT", "off");
|
||||
/**
|
||||
* 完整配置参考 gov.nist.javax.sip.SipStackImpl,需要下载源码
|
||||
* gov/nist/javax/sip/SipStackImpl.class
|
||||
* sip消息的解析在 gov.nist.javax.sip.stack.UDPMessageChannel的processIncomingDataPacket方法
|
||||
*/
|
||||
|
||||
// * gov/nist/javax/sip/SipStackImpl.class
|
||||
// 接收所有notify请求,即使没有订阅
|
||||
properties.setProperty("gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY", "true");
|
||||
properties.setProperty("gov.nist.javax.sip.AUTOMATIC_DIALOG_ERROR_HANDLING", "false");
|
||||
properties.setProperty("gov.nist.javax.sip.CANCEL_CLIENT_TRANSACTION_CHECKED", "true");
|
||||
// 为_NULL _对话框传递_终止的_事件
|
||||
properties.setProperty("gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG", "true");
|
||||
// 是否自动计算content length的实际长度,默认不计算
|
||||
properties.setProperty("gov.nist.javax.sip.COMPUTE_CONTENT_LENGTH_FROM_MESSAGE_BODY", "true");
|
||||
// 会话清理策略
|
||||
properties.setProperty("gov.nist.javax.sip.RELEASE_REFERENCES_STRATEGY", "Normal");
|
||||
// 处理由该服务器处理的基于底层TCP的保持生存超时
|
||||
properties.setProperty("gov.nist.javax.sip.RELIABLE_CONNECTION_KEEP_ALIVE_TIMEOUT", "60");
|
||||
// 获取实际内容长度,不使用header中的长度信息
|
||||
properties.setProperty("gov.nist.javax.sip.COMPUTE_CONTENT_LENGTH_FROM_MESSAGE_BODY", "true");
|
||||
// 线程可重入
|
||||
properties.setProperty("gov.nist.javax.sip.REENTRANT_LISTENER", "true");
|
||||
// 定义应用程序打算多久审计一次 SIP 堆栈,了解其内部线程的健康状况(该属性指定连续审计之间的时间(以毫秒为单位))
|
||||
properties.setProperty("gov.nist.javax.sip.THREAD_AUDIT_INTERVAL_IN_MILLISECS", "30000");
|
||||
|
||||
// properties.setProperty("gov.nist.javax.sip.MESSAGE_PROCESSOR_FACTORY", "gov.nist.javax.sip.stack.NioMessageProcessorFactory");
|
||||
|
||||
/**
|
||||
* sip_server_log.log 和 sip_debug_log.log ERROR, INFO, WARNING, OFF, DEBUG, TRACE
|
||||
*/
|
||||
Logger logger = LoggerFactory.getLogger(SipConfig.class);
|
||||
if (sipLog) {
|
||||
properties.setProperty("gov.nist.javax.sip.STACK_LOGGER", "cn.skcks.docking.gb28181.core.sip.logger.StackLoggerImpl");
|
||||
properties.setProperty("gov.nist.javax.sip.SERVER_LOGGER", "cn.skcks.docking.gb28181.core.sip.logger.ServerLoggerImpl");
|
||||
properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "true");
|
||||
logger.info("[SIP日志]已开启");
|
||||
}else {
|
||||
logger.info("[SIP日志]已关闭");
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package cn.skcks.docking.gb28181.starter;
|
||||
|
||||
import cn.skcks.docking.gb28181.common.json.JsonUtils;
|
||||
import cn.skcks.docking.gb28181.config.sip.SipConfig;
|
||||
import cn.skcks.docking.gb28181.core.sip.SipService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Order(0)
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class SipStarter implements SmartLifecycle {
|
||||
private final SipConfig sipConfig;
|
||||
private final SipService sipService;
|
||||
|
||||
private boolean isRunning;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if(checkConfig()){
|
||||
isRunning = true;
|
||||
log.debug("sip 服务 启动");
|
||||
sipService.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
log.debug("sip 服务 关闭");
|
||||
sipService.stop();
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
public boolean checkConfig(){
|
||||
log.debug("sip 配置信息 => \n{}", JsonUtils.toJson(sipConfig));
|
||||
if(CollectionUtils.isEmpty(sipConfig.getIp())){
|
||||
log.error("sip ip 配置错误, 请检查配置是否正确");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -21,6 +21,12 @@
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.skcks.docking.gb28181</groupId>
|
||||
<artifactId>gb28181-service</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.skcks.docking.gb28181</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
|
25
starter/src/test/resources/application.yml
Normal file
25
starter/src/test/resources/application.yml
Normal file
@ -0,0 +1,25 @@
|
||||
server:
|
||||
port: 28181
|
||||
|
||||
gb28181:
|
||||
# 作为28181服务器的配置
|
||||
sip:
|
||||
# [必须修改] 本机的IP,对应你的网卡,监听什么ip就是使用什么网卡,
|
||||
# 如果不明白,就使用0.0.0.0,大部分情况都是可以的
|
||||
# 请不要使用127.0.0.1,任何包括localhost在内的域名都是不可以的。
|
||||
ip:
|
||||
- 10.10.10.20
|
||||
- 10.27.0.6
|
||||
# [可选] 28181服务监听的端口
|
||||
port: 5060
|
||||
# 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007)
|
||||
# 后两位为行业编码,定义参照附录D.3
|
||||
# 3701020049标识山东济南历下区 信息行业接入
|
||||
# [可选]
|
||||
domain: 4405010000
|
||||
# [可选]
|
||||
id: 44050100002000000002
|
||||
# [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验
|
||||
password: 123456
|
||||
# 是否存储alarm信息
|
||||
alarm: true
|
Loading…
Reference in New Issue
Block a user