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>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</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>
|
</project>
|
||||||
|
@ -80,6 +80,11 @@
|
|||||||
<groupId>redis.clients</groupId>
|
<groupId>redis.clients</groupId>
|
||||||
<artifactId>jedis</artifactId>
|
<artifactId>jedis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<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>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<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协议栈 -->
|
<!-- sip协议栈 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.sip</groupId>
|
<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>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.skcks.docking.gb28181</groupId>
|
||||||
|
<artifactId>gb28181-service</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.skcks.docking.gb28181</groupId>
|
<groupId>cn.skcks.docking.gb28181</groupId>
|
||||||
<artifactId>common</artifactId>
|
<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