Merge branch 'wvp-28181-2.0' into wvp-28181-2.0

This commit is contained in:
hotcoffie 2021-12-01 20:35:16 +08:00 committed by GitHub
commit 3a20750c2f
192 changed files with 7403 additions and 18514 deletions

10
.github/ISSUE_TEMPLATE/-------.md vendored Normal file
View File

@ -0,0 +1,10 @@
---
name: "[ 新功能 ]"
about: 新功能
title: ''
labels: ''
assignees: ''
---

29
.github/ISSUE_TEMPLATE/--bug---.md vendored Normal file
View File

@ -0,0 +1,29 @@
---
name: "[ BUG ] "
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**描述错误**
描述下您遇到的问题
**如何复现**
有明确复现步骤的问题会很容易被解决
**预期行为**
清晰简洁的描述您期望发生的事情
**截图**
**环境信息:**
- 1. 部署方式 wvp-pro docker / zlm(docker) + 编译wvp-pro/ wvp-prp + zlm都是编译部署/
- 2. 部署环境 windows / ubuntu/ centos ...
- 3. 端口开放情况
- 4. 是否是公网部署
- 5. 是否使用https
- 6. 方便的话提供下使用的设备品牌或平台
- 7. 你做过哪些尝试

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "be.teletask.onvif-java"] [submodule "be.teletask.onvif-java"]
path = be.teletask.onvif-java path = be.teletask.onvif-java
url = https://gitee.com/18010473990/be.teletask.onvif-java.git url = https://gitee.com/pan648540858/be.teletask.onvif-java.git

View File

@ -1,4 +1,4 @@
![logo](https://gitee.com/18010473990/wvp-GB28181/raw/wvp-28181-2.0/web_src/static/logo.png) ![logo](https://gitee.com/pan648540858/wvp-GB28181-pro/raw/wvp-28181-2.0/web_src/static/logo.png)
# 开箱即用的的28181协议视频平台 # 开箱即用的的28181协议视频平台
[![Build Status](https://travis-ci.org/xia-chu/ZLMediaKit.svg?branch=master)](https://travis-ci.org/xia-chu/ZLMediaKit) [![Build Status](https://travis-ci.org/xia-chu/ZLMediaKit.svg?branch=master)](https://travis-ci.org/xia-chu/ZLMediaKit)
@ -13,13 +13,7 @@ WEB VIDEO PLATFORM是一个基于GB28181-2016标准实现的开箱即用的网
流媒体服务基于ZLMediaKit-https://github.com/xiongziliang/ZLMediaKit 流媒体服务基于ZLMediaKit-https://github.com/xiongziliang/ZLMediaKit
前端页面基于MediaServerUI进行修改. 前端页面基于MediaServerUI进行修改.
# 快速体验
```shell
docker pull 648540858/wvp_pro
docker run --env WVP_IP="你的IP" -it -p 18080:18080 -p 30000-30500:30000-30500/udp -p 30000-30500:30000-30500/tcp -p 80:80 -p 5060:5060 -p 5060:5060/udp 648540858/wvp_pro
```
docker使用详情查看[https://hub.docker.com/r/648540858/wvp_pro](https://hub.docker.com/r/648540858/wvp_pro)
# 应用场景: # 应用场景:
支持浏览器无插件播放摄像头视频。 支持浏览器无插件播放摄像头视频。
支持摄像机、平台、NVR等设备接入。 支持摄像机、平台、NVR等设备接入。
@ -34,7 +28,7 @@ docker使用详情查看[https://hub.docker.com/r/648540858/wvp_pro](https://
[https://github.com/648540858/wvp-GB28181-pro/wiki](https://github.com/648540858/wvp-GB28181-pro/wiki) [https://github.com/648540858/wvp-GB28181-pro/wiki](https://github.com/648540858/wvp-GB28181-pro/wiki)
# gitee同步仓库 # gitee同步仓库
https://gitee.com/18010473990/wvp-GB28181.git https://gitee.com/pan648540858/wvp-GB28181-pro.git
# 截图 # 截图
![build_1.png](https://github.com/648540858/wiki/blob/master/images/Screenshot_1.png) ![build_1.png](https://github.com/648540858/wiki/blob/master/images/Screenshot_1.png)
@ -106,20 +100,28 @@ https://gitee.com/18010473990/wvp-GB28181.git
- [ ] 添加ONVIF探测局域网内的设备 - [ ] 添加ONVIF探测局域网内的设备
- [X] 添加RTMP视频 - [X] 添加RTMP视频
- [X] 云端录像(需要部署单独服务配合使用) - [X] 云端录像(需要部署单独服务配合使用)
- [X] 多流媒体节点,自动选择负载最低的节点使用。
- [X] 支持使用mysql作为数据库默认sqlite3,开箱即用。 - [X] 支持使用mysql作为数据库默认sqlite3,开箱即用。
- [ ] 添加系统配置 - [ ] 添加系统配置
- [ ] 添加用户管理 - [ ] 添加用户管理
- [X] WEB端支持播放H264与H265音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。 - [X] WEB端支持播放H264与H265音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。
# docker快速体验
```shell
docker pull 648540858/wvp_pro
docker run --env WVP_IP="你的IP" -it -p 18080:18080 -p 30000-30500:30000-30500/udp -p 30000-30500:30000-30500/tcp -p 80:80 -p 5060:5060 -p 5060:5060/udp 648540858/wvp_pro
```
docker使用详情查看[https://hub.docker.com/r/648540858/wvp_pro](https://hub.docker.com/r/648540858/wvp_pro)
# gitee同步仓库 # gitee同步仓库
https://gitee.com/18010473990/wvp-GB28181.git https://gitee.com/pan648540858/wvp-GB28181-pro.git
# 使用帮助 # 使用帮助
QQ群: 901799015, 690854210(ZLM大群) QQ群: 901799015, 690854210(ZLM大群)
QQ私信一般不回, 精力有限.欢迎大家在群里讨论.觉得项目对你有帮助欢迎star和提交pr。 QQ私信一般不回, 精力有限.欢迎大家在群里讨论.觉得项目对你有帮助欢迎star和提交pr。
# 致谢 # 致谢
感谢作者[夏楚](https://github.com/xia-chu) 提供这么棒的开源流媒体服务框架 感谢作者[夏楚](https://github.com/xia-chu) 提供这么棒的开源流媒体服务框架

Binary file not shown.

11
pom.xml
View File

@ -212,17 +212,6 @@
<!-- <version>1.0.8</version>--> <!-- <version>1.0.8</version>-->
<!-- </dependency>--> <!-- </dependency>-->
<!-- onvif协议栈 -->
<dependency>
<groupId>be.teletask</groupId>
<artifactId>onvif-java</artifactId>
<version>1.0.2</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/onvif-java-1.0.2.jar</systemPath>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>

View File

@ -23,6 +23,7 @@ create table device
updateTime varchar(50) not null, updateTime varchar(50) not null,
port int not null, port int not null,
expires int not null, expires int not null,
subscribeCycleForCatalog int not null,
hostAddress varchar(50) not null, hostAddress varchar(50) not null,
charset varchar(50) not null charset varchar(50) not null
); );
@ -207,6 +208,7 @@ create table stream_proxy
enable_hls bit null, enable_hls bit null,
enable_mp4 bit null, enable_mp4 bit null,
enable bit not null, enable bit not null,
enable_remove_none_reader bit not null,
createTime varchar(50) not null, createTime varchar(50) not null,
primary key (app, stream) primary key (app, stream)
); );

View File

@ -6,6 +6,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import springfox.documentation.oas.annotations.EnableOpenApi; import springfox.documentation.oas.annotations.EnableOpenApi;

View File

@ -30,7 +30,7 @@ public class StreamInfo {
private String rtsps; private String rtsps;
private String rtc; private String rtc;
private String mediaServerId; private String mediaServerId;
private JSONArray tracks; private Object tracks;
public static class TransactionInfo{ public static class TransactionInfo{
public String callId; public String callId;
@ -105,11 +105,11 @@ public class StreamInfo {
this.rtsp = rtsp; this.rtsp = rtsp;
} }
public JSONArray getTracks() { public Object getTracks() {
return tracks; return tracks;
} }
public void setTracks(JSONArray tracks) { public void setTracks(Object tracks) {
this.tracks = tracks; this.tracks = tracks;
} }

View File

@ -1,14 +1,16 @@
package com.genersoft.iot.vmp.common; package com.genersoft.iot.vmp.common;
/** /**
* @Description: 定义常量 * @description: 定义常量
* @author: swwheihei * @author: swwheihei
* @date: 2019年5月30日 下午3:04:04 * @date: 2019年5月30日 下午3:04:04
* *
*/ */
public class VideoManagerConstants { public class VideoManagerConstants {
public static final String WVP_SERVER_PREFIX = "VMP_wvp_server"; public static final String WVP_SERVER_PREFIX = "VMP_SIGNALLING_SERVER_INFO_";
public static final String WVP_SERVER_STREAM_PUSH_PREFIX = "VMP_SIGNALLING_STREAM_PUSH_";
public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_"; public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_";
@ -25,6 +27,7 @@ public class VideoManagerConstants {
public static final String PLAYER_PREFIX = "VMP_PLAYER_"; public static final String PLAYER_PREFIX = "VMP_PLAYER_";
public static final String PLAY_BLACK_PREFIX = "VMP_PLAYBACK_"; public static final String PLAY_BLACK_PREFIX = "VMP_PLAYBACK_";
public static final String DOWNLOAD_PREFIX = "VMP_DOWNLOAD_";
public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_PLATFORM_KEEPLIVE_"; public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_PLATFORM_KEEPLIVE_";
@ -51,4 +54,7 @@ public class VideoManagerConstants {
public static final String MEDIA_SSRC_USED_PREFIX = "VMP_media_used_ssrc_"; public static final String MEDIA_SSRC_USED_PREFIX = "VMP_media_used_ssrc_";
public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_media_transaction_"; public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_media_transaction_";
//************************** redis 消息*********************************
public static final String WVP_MSG_STREAM_PUSH_CHANGE_PREFIX = "WVP_MSG_STREAM_PUSH_CHANGE";
} }

View File

@ -0,0 +1,43 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
/**
* 动态定时任务
*/
@Component
public class DynamicTask {
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
private Map<String, ScheduledFuture<?>> futureMap = new ConcurrentHashMap<>();
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
return new ThreadPoolTaskScheduler();
}
public String startCron(String key, Runnable task, int cycleForCatalog) {
stopCron(key);
// scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period cycleForCatalog表示执行的间隔
ScheduledFuture future = threadPoolTaskScheduler.scheduleWithFixedDelay(task, cycleForCatalog * 1000L);
futureMap.put(key, future);
return "startCron";
}
public void stopCron(String key) {
if (futureMap.get(key) != null && !futureMap.get(key).isCancelled()) {
futureMap.get(key).cancel(true);
}
}
}

View File

@ -163,9 +163,9 @@ public class ProxyServletConfig {
* 异常处理 * 异常处理
*/ */
@Override @Override
protected void handleRequestException(HttpRequest proxyRequest, HttpResponse proxyResonse, Exception e){ protected void handleRequestException(HttpRequest proxyRequest, HttpResponse proxyResponse, Exception e){
try { try {
super.handleRequestException(proxyRequest, proxyResonse, e); super.handleRequestException(proxyRequest, proxyResponse, e);
} catch (ServletException servletException) { } catch (ServletException servletException) {
logger.error("录像服务 代理失败: ", e); logger.error("录像服务 代理失败: ", e);
} catch (IOException ioException) { } catch (IOException ioException) {

View File

@ -16,7 +16,7 @@ import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisPoolConfig;
/** /**
* @Description:Redis中间件配置类使用spring-data-redis集成自动从application.yml中加载redis配置 * @description:Redis中间件配置类使用spring-data-redis集成自动从application.yml中加载redis配置
* @author: swwheihei * @author: swwheihei
* @date: 2019年5月30日 上午10:58:25 * @date: 2019年5月30日 上午10:58:25
* *

View File

@ -1,9 +1,7 @@
package com.genersoft.iot.vmp.conf; package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@ -27,7 +25,7 @@ public class SipConfig {
Integer ptzSpeed = 50; Integer ptzSpeed = 50;
Integer keepaliveTimeOut = 180; Integer keepaliveTimeOut = 255;
Integer registerTimeInterval = 60; Integer registerTimeInterval = 60;

View File

@ -32,5 +32,7 @@ public class SipDeviceRunner implements CommandLineRunner {
for (String deviceId : onlineForAll) { for (String deviceId : onlineForAll) {
storager.online(deviceId); storager.online(deviceId);
} }
// TODO 查询在线设备那些开启了订阅为设备开启定时的目录订阅
} }
} }

View File

@ -0,0 +1,59 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync(proxyTargetClass = true)
public class ThreadPoolTaskConfig {
public static final int cpuNum = Runtime.getRuntime().availableProcessors();
/**
* 默认情况下在创建了线程池后线程池中的线程数为0当有任务来之后就会创建一个线程去执行任务
* 当线程池中的线程数目达到corePoolSize后就会把到达的任务放到缓存队列当中
* 当队列满了就继续创建线程当线程数量大于等于maxPoolSize后开始使用拒绝策略拒绝
*/
/**
* 核心线程数默认线程数
*/
private static final int corePoolSize = cpuNum;
/**
* 最大线程数
*/
private static final int maxPoolSize = cpuNum*2;
/**
* 允许线程空闲时间单位默认为秒
*/
private static final int keepAliveTime = 30;
/**
* 缓冲队列大小
*/
private static final int queueCapacity = 500;
/**
* 线程池名前缀
*/
private static final String threadNamePrefix = "wvp-sip-handle-";
@Bean("taskExecutor") // bean的名称默认为首字母小写的方法名
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setThreadNamePrefix(threadNamePrefix);
// 线程池对拒绝任务的处理策略
// CallerRunsPolicy由调用线程提交任务的线程处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}

View File

@ -27,6 +27,8 @@ public class UserSetup {
private Boolean logInDatebase = Boolean.TRUE; private Boolean logInDatebase = Boolean.TRUE;
private String serverId = "000000";
private List<String> interfaceAuthenticationExcludes = new ArrayList<>(); private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
public Boolean getSavePositionHistory() { public Boolean getSavePositionHistory() {
@ -104,4 +106,12 @@ public class UserSetup {
public void setLogInDatebase(Boolean logInDatebase) { public void setLogInDatebase(Boolean logInDatebase) {
this.logInDatebase = logInDatebase; this.logInDatebase = logInDatebase;
} }
public String getServerId() {
return serverId;
}
public void setServerId(String serverId) {
this.serverId = serverId;
}
} }

View File

@ -1,25 +0,0 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* @Description: 获取数据库配置
* @author: swwheihei
* @date: 2020年5月6日 下午2:46:00
*/
@Configuration("vmConfig")
public class VManagerConfig {
@Value("${spring.application.database:redis}")
private String database;
public String getDatabase() {
return database;
}
public void setDatabase(String database) {
this.database = database;
}
}

View File

@ -1,7 +1,10 @@
package com.genersoft.iot.vmp.conf; package com.genersoft.iot.vmp.conf;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -12,13 +15,22 @@ public class WVPTimerTask {
private IRedisCatchStorage redisCatchStorage; private IRedisCatchStorage redisCatchStorage;
@Autowired @Autowired
private SipConfig sipConfig; private IMediaServerService mediaServerService;
@Autowired @Autowired
private MediaConfig mediaConfig; private UserSetup userSetup;
@Scheduled(cron="0/2 * * * * ? ") //每3秒执行一次 @Value("${server.port}")
private int serverPort;
@Autowired
private SipConfig sipConfig;
@Scheduled(fixedRate = 2 * 1000) //每3秒执行一次
public void execute(){ public void execute(){
// redisCatchStorage.updateWVPInfo(); JSONObject jsonObject = new JSONObject();
jsonObject.put("ip", sipConfig.getIp());
jsonObject.put("port", serverPort);
redisCatchStorage.updateWVPInfo(userSetup.getServerId(), jsonObject, 3);
} }
} }

View File

@ -34,7 +34,7 @@ public class LoginFailureHandler implements AuthenticationFailureHandler {
} else if (e instanceof BadCredentialsException) { } else if (e instanceof BadCredentialsException) {
// 密码错误 // 密码错误
logger.info("[登录失败] - 用户[{}]密码错误", username); logger.info("[登录失败] - 用户[{}]密码/SIP服务器ID 错误", username);
} else if (e instanceof CredentialsExpiredException) { } else if (e instanceof CredentialsExpiredException) {
// 密码过期 // 密码过期

View File

@ -1,18 +1,11 @@
package com.genersoft.iot.vmp.gb28181; package com.genersoft.iot.vmp.gb28181;
import java.text.ParseException; import com.genersoft.iot.vmp.conf.SipConfig;
import java.util.Properties;
import java.util.TooManyListenersException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.sip.*;
import javax.sip.header.CallIdHeader;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.ISIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import gov.nist.javax.sip.SipProviderImpl; import gov.nist.javax.sip.SipProviderImpl;
import gov.nist.javax.sip.SipStackImpl;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -20,14 +13,15 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.conf.SipConfig; import javax.sip.*;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorFactory; import java.util.Properties;
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; import java.util.TooManyListenersException;
import java.util.concurrent.LinkedBlockingQueue;
import gov.nist.javax.sip.SipStackImpl; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Component @Component
public class SipLayer implements SipListener { public class SipLayer{
private final static Logger logger = LoggerFactory.getLogger(SipLayer.class); private final static Logger logger = LoggerFactory.getLogger(SipLayer.class);
@ -35,33 +29,14 @@ public class SipLayer implements SipListener {
private SipConfig sipConfig; private SipConfig sipConfig;
@Autowired @Autowired
private SIPProcessorFactory processorFactory; private ISIPProcessorObserver sipProcessorObserver;
@Autowired
private SipSubscribe sipSubscribe;
private SipStackImpl sipStack; private SipStackImpl sipStack;
private SipFactory sipFactory; private SipFactory sipFactory;
/**
* 消息处理器线程池
*/
private ThreadPoolExecutor processThreadPool;
@Bean("initSipServer")
private ThreadPoolExecutor initSipServer() {
int processThreadNum = Runtime.getRuntime().availableProcessors() * 10;
LinkedBlockingQueue<Runnable> processQueue = new LinkedBlockingQueue<>(10000);
processThreadPool = new ThreadPoolExecutor(processThreadNum,processThreadNum,
0L,TimeUnit.MILLISECONDS,processQueue,
new ThreadPoolExecutor.CallerRunsPolicy());
return processThreadPool;
}
@Bean("sipFactory") @Bean("sipFactory")
@DependsOn("initSipServer")
private SipFactory createSipFactory() { private SipFactory createSipFactory() {
sipFactory = SipFactory.getInstance(); sipFactory = SipFactory.getInstance();
sipFactory.setPathName("gov.nist"); sipFactory.setPathName("gov.nist");
@ -69,7 +44,7 @@ public class SipLayer implements SipListener {
} }
@Bean("sipStack") @Bean("sipStack")
@DependsOn({"initSipServer", "sipFactory"}) @DependsOn({"sipFactory"})
private SipStack createSipStack() throws PeerUnavailableException { private SipStack createSipStack() throws PeerUnavailableException {
Properties properties = new Properties(); Properties properties = new Properties();
properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP");
@ -87,7 +62,7 @@ public class SipLayer implements SipListener {
return sipStack; return sipStack;
} }
@Bean("tcpSipProvider") @Bean(name = "tcpSipProvider")
@DependsOn("sipStack") @DependsOn("sipStack")
private SipProviderImpl startTcpListener() { private SipProviderImpl startTcpListener() {
ListeningPoint tcpListeningPoint = null; ListeningPoint tcpListeningPoint = null;
@ -95,7 +70,7 @@ public class SipLayer implements SipListener {
try { try {
tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "TCP"); tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "TCP");
tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint); tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint);
tcpSipProvider.addSipListener(this); tcpSipProvider.addSipListener(sipProcessorObserver);
logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getMonitorIp() + ":" + sipConfig.getPort() + "}"); logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getMonitorIp() + ":" + sipConfig.getPort() + "}");
} catch (TransportNotSupportedException e) { } catch (TransportNotSupportedException e) {
e.printStackTrace(); e.printStackTrace();
@ -110,7 +85,7 @@ public class SipLayer implements SipListener {
return tcpSipProvider; return tcpSipProvider;
} }
@Bean("udpSipProvider") @Bean(name = "udpSipProvider")
@DependsOn("sipStack") @DependsOn("sipStack")
private SipProviderImpl startUdpListener() { private SipProviderImpl startUdpListener() {
ListeningPoint udpListeningPoint = null; ListeningPoint udpListeningPoint = null;
@ -118,8 +93,7 @@ public class SipLayer implements SipListener {
try { try {
udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "UDP"); udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "UDP");
udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint); udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint);
udpSipProvider.addSipListener(this); udpSipProvider.addSipListener(sipProcessorObserver);
// udpSipProvider.setAutomaticDialogSupportEnabled(false);
} catch (TransportNotSupportedException e) { } catch (TransportNotSupportedException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InvalidArgumentException e) { } catch (InvalidArgumentException e) {
@ -134,123 +108,4 @@ public class SipLayer implements SipListener {
return udpSipProvider; return udpSipProvider;
} }
/**
* SIP服务端接收消息的方法 Content 里面是GBK编码 This method is called by the SIP stack when a
* new request arrives.
*/
@Override
public void processRequest(RequestEvent evt) {
logger.debug(evt.getRequest().toString());
// 由于jainsip是单线程程序为提高性能并发处理
processThreadPool.execute(() -> {
if (processorFactory != null) {
processorFactory.createRequestProcessor(evt).process();
}
});
}
@Override
public void processResponse(ResponseEvent evt) {
Response response = evt.getResponse();
logger.debug(evt.getResponse().toString());
int status = response.getStatusCode();
if (((status >= 200) && (status < 300)) || status == 401) { // Success!
ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
try {
processor.process(evt, this, sipConfig);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (evt.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) {
CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
subscribe.response(evt);
}
}
}
} else if ((status >= 100) && (status < 200)) {
// 增加其它无需回复的响应如101180等
} else {
logger.warn("接收到失败的response响应status" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/);
if (evt.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) {
CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
subscribe.response(evt);
}
}
}
}
}
/**
* <p>
* Title: processTimeout
* </p>
* <p>
* Description:
* </p>
*
* @param timeoutEvent
*/
@Override
public void processTimeout(TimeoutEvent timeoutEvent) {
// TODO Auto-generated method stub
}
/**
* <p>
* Title: processIOException
* </p>
* <p>
* Description:
* </p>
*
* @param exceptionEvent
*/
@Override
public void processIOException(IOExceptionEvent exceptionEvent) {
// TODO Auto-generated method stub
}
/**
* <p>
* Title: processTransactionTerminated
* </p>
* <p>
* Description:
* </p>
*
* @param transactionTerminatedEvent
*/
@Override
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
// TODO Auto-generated method stub
}
/**
* <p>
* Title: processDialogTerminated
* </p>
* <p>
* Description:
* </p>
*
* @param dialogTerminatedEvent
*/
@Override
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
// TODO Auto-generated method stub
}
} }

View File

@ -9,7 +9,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
/** /**
* @Description:注册逻辑处理当设备注册后触发逻辑 * @description:注册逻辑处理当设备注册后触发逻辑
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 下午9:41:46 * @date: 2020年5月8日 下午9:41:46
*/ */

View File

@ -109,6 +109,11 @@ public class Device {
*/ */
private String charset ; private String charset ;
/**
* 目录订阅周期0为不订阅
*/
private int subscribeCycleForCatalog ;
public String getDeviceId() { public String getDeviceId() {
@ -270,4 +275,12 @@ public class Device {
public void setCharset(String charset) { public void setCharset(String charset) {
this.charset = charset; this.charset = charset;
} }
public int getSubscribeCycleForCatalog() {
return subscribeCycleForCatalog;
}
public void setSubscribeCycleForCatalog(int subscribeCycleForCatalog) {
this.subscribeCycleForCatalog = subscribeCycleForCatalog;
}
} }

View File

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.gb28181.bean; package com.genersoft.iot.vmp.gb28181.bean;
/** /**
* @Description: 移动位置bean * @description: 移动位置bean
* @author: lawrencehj * @author: lawrencehj
* @date: 2021年1月23日 * @date: 2021年1月23日
*/ */

View File

@ -6,14 +6,18 @@ package com.genersoft.iot.vmp.gb28181.bean;
import java.util.List; import java.util.List;
/** /**
* @Description:设备录像信息bean * @description:设备录像信息bean
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 下午2:05:56 * @date: 2020年5月8日 下午2:05:56
*/ */
public class RecordInfo { public class RecordInfo {
private String deviceId; private String deviceId;
private String channelId;
private String sn;
private String name; private String name;
private int sumNum; private int sumNum;
@ -52,4 +56,19 @@ public class RecordInfo {
this.recordList = recordList; this.recordList = recordList;
} }
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
} }

View File

@ -8,7 +8,7 @@ import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
/** /**
* @Description:设备录像bean * @description:设备录像bean
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 下午2:06:54 * @date: 2020年5月8日 下午2:06:54
*/ */

View File

@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
/** /**
* @Description:设备离在线状态检测器用于检测设备状态 * @description:设备离在线状态检测器用于检测设备状态
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月13日 下午2:40:29 * @date: 2020年5月13日 下午2:40:29
*/ */

View File

@ -13,7 +13,7 @@ import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent;
import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent; import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent;
/** /**
* @Description:Event事件通知推送器支持推送在线事件离线事件 * @description:Event事件通知推送器支持推送在线事件离线事件
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午11:30:50 * @date: 2020年5月6日 上午11:30:50
*/ */

View File

@ -1,38 +1,127 @@
package com.genersoft.iot.vmp.gb28181.event; package com.genersoft.iot.vmp.gb28181.event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.sip.ResponseEvent; import javax.sip.*;
import javax.sip.header.CallIdHeader;
import javax.sip.message.Response;
import java.util.Calendar;
import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@Component @Component
public class SipSubscribe { public class SipSubscribe {
private final Logger logger = LoggerFactory.getLogger(SipSubscribe.class);
private Map<String, SipSubscribe.Event> errorSubscribes = new ConcurrentHashMap<>(); private Map<String, SipSubscribe.Event> errorSubscribes = new ConcurrentHashMap<>();
private Map<String, SipSubscribe.Event> okSubscribes = new ConcurrentHashMap<>(); private Map<String, SipSubscribe.Event> okSubscribes = new ConcurrentHashMap<>();
private Map<String, Date> timeSubscribes = new ConcurrentHashMap<>();
// @Scheduled(cron="*/5 * * * * ?") //每五秒执行一次
// @Scheduled(fixedRate= 100 * 60 * 60 )
@Scheduled(cron="0 0 * * * ?") //每小时执行一次 每个整点
public void execute(){
logger.info("[定时任务] 清理过期的订阅信息");
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.set(Calendar.HOUR, calendar.get(Calendar.HOUR) - 1);
for (String key : timeSubscribes.keySet()) {
if (timeSubscribes.get(key).before(calendar.getTime())){
logger.info("[定时任务] 清理过期的订阅信息: {}", key);
errorSubscribes.remove(key);
okSubscribes.remove(key);
timeSubscribes.remove(key);
}
}
}
public interface Event { public interface Event {
void response(ResponseEvent event); void response(EventResult eventResult);
}
public static class EventResult<EventObject>{
public int statusCode;
public String type;
public String msg;
public String callId;
public Dialog dialog;
public EventObject event;
public EventResult() {
}
public EventResult(EventObject event) {
this.event = event;
if (event instanceof ResponseEvent) {
ResponseEvent responseEvent = (ResponseEvent)event;
Response response = responseEvent.getResponse();
this.dialog = responseEvent.getDialog();
this.type = "response";
if (response != null) {
this.msg = response.getReasonPhrase();
this.statusCode = response.getStatusCode();
}
this.callId = ((CallIdHeader)response.getHeader(CallIdHeader.NAME)).getCallId();
}else if (event instanceof TimeoutEvent) {
TimeoutEvent timeoutEvent = (TimeoutEvent)event;
this.type = "timeout";
this.msg = "消息超时未回复";
this.statusCode = -1024;
this.callId = timeoutEvent.getClientTransaction().getDialog().getCallId().getCallId();
this.dialog = timeoutEvent.getClientTransaction().getDialog();
}else if (event instanceof TransactionTerminatedEvent) {
TransactionTerminatedEvent transactionTerminatedEvent = (TransactionTerminatedEvent)event;
this.type = "transactionTerminated";
this.msg = "事务已结束";
this.statusCode = -1024;
this.callId = transactionTerminatedEvent.getClientTransaction().getDialog().getCallId().getCallId();
this.dialog = transactionTerminatedEvent.getClientTransaction().getDialog();
}else if (event instanceof DialogTerminatedEvent) {
DialogTerminatedEvent dialogTerminatedEvent = (DialogTerminatedEvent)event;
this.type = "dialogTerminated";
this.msg = "会话已结束";
this.statusCode = -1024;
this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId();
this.dialog = dialogTerminatedEvent.getDialog();
}
}
} }
public void addErrorSubscribe(String key, SipSubscribe.Event event) { public void addErrorSubscribe(String key, SipSubscribe.Event event) {
errorSubscribes.put(key, event); errorSubscribes.put(key, event);
timeSubscribes.put(key, new Date());
} }
public void addOkSubscribe(String key, SipSubscribe.Event event) { public void addOkSubscribe(String key, SipSubscribe.Event event) {
okSubscribes.put(key, event); okSubscribes.put(key, event);
timeSubscribes.put(key, new Date());
} }
public SipSubscribe.Event getErrorSubscribe(String key) { public SipSubscribe.Event getErrorSubscribe(String key) {
return errorSubscribes.get(key); return errorSubscribes.get(key);
} }
public void removeErrorSubscribe(String key) {
errorSubscribes.remove(key);
timeSubscribes.remove(key);
}
public SipSubscribe.Event getOkSubscribe(String key) { public SipSubscribe.Event getOkSubscribe(String key) {
return okSubscribes.get(key); return okSubscribes.get(key);
} }
public void removeOkSubscribe(String key) {
okSubscribes.remove(key);
timeSubscribes.remove(key);
}
public int getErrorSubscribesSize(){ public int getErrorSubscribesSize(){
return errorSubscribes.size(); return errorSubscribes.size();
} }

View File

@ -12,7 +12,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
/** /**
* @Description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件 * @description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午11:35:46 * @date: 2020年5月6日 上午11:35:46
*/ */
@ -39,10 +39,6 @@ public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessa
// 获取失效的key // 获取失效的key
String expiredKey = message.toString(); String expiredKey = message.toString();
logger.debug(expiredKey); logger.debug(expiredKey);
if(!expiredKey.startsWith(VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX)){
logger.debug("收到redis过期监听但开头不是"+VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX+",忽略");
return;
}
// 平台心跳到期,需要重发, 判断是否已经多次未收到心跳回复, 多次未收到,则重新发起注册, 注册尝试多次未得到回复,则认为平台离线 // 平台心跳到期,需要重发, 判断是否已经多次未收到心跳回复, 多次未收到,则重新发起注册, 注册尝试多次未得到回复,则认为平台离线
if (expiredKey.startsWith(VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX)) { if (expiredKey.startsWith(VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX)) {
String platformGBId = expiredKey.substring(VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX.length(),expiredKey.length()); String platformGBId = expiredKey.substring(VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX.length(),expiredKey.length());

View File

@ -12,7 +12,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
/** /**
* @Description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件 * @description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午11:35:46 * @date: 2020年5月6日 上午11:35:46
*/ */

View File

@ -3,7 +3,7 @@ package com.genersoft.iot.vmp.gb28181.event.offline;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
/** /**
* @Description: 离线事件类 * @description: 离线事件类
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午11:33:13 * @date: 2020年5月6日 上午11:33:13
*/ */

View File

@ -11,8 +11,8 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
/** /**
* @Description: 离线事件监听器监听到离线后修改设备离在线状态 设备离线有两个来源 * @description: 离线事件监听器监听到离线后修改设备离在线状态 设备离线有两个来源
* 1设备主动注销发送注销指令{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor} * 1设备主动注销发送注销指令{@link com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.RegisterRequestProcessor}
* 2设备未知原因离线心跳超时,{@link com.genersoft.iot.vmp.gb28181.event.offline.OfflineEventListener} * 2设备未知原因离线心跳超时,{@link com.genersoft.iot.vmp.gb28181.event.offline.OfflineEventListener}
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 下午1:51:23 * @date: 2020年5月6日 下午1:51:23
@ -54,5 +54,8 @@ public class OfflineEventListener implements ApplicationListener<OfflineEvent> {
// 处理离线监听 // 处理离线监听
storager.outline(event.getDeviceId()); storager.outline(event.getDeviceId());
// TODO 离线取消订阅
} }
} }

View File

@ -4,7 +4,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
/** /**
* @Description: 在线事件类 * @description: 在线事件类
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午11:32:56 * @date: 2020年5月6日 上午11:32:56
*/ */

View File

@ -13,12 +13,11 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date;
/** /**
* @Description: 在线事件监听器监听到离线后修改设备离在线状态 设备在线有两个来源 * @description: 在线事件监听器监听到离线后修改设备离在线状态 设备在线有两个来源
* 1设备主动注销发送注销指令{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor} * 1设备主动注销发送注销指令
* 2设备未知原因离线心跳超时,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor} * 2设备未知原因离线心跳超时
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 下午1:51:23 * @date: 2020年5月6日 下午1:51:23
*/ */
@ -74,5 +73,8 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
device.setOnline(1); device.setOnline(1);
// 处理上线监听 // 处理上线监听
storager.updateDevice(device); storager.updateDevice(device);
// TODO 上线添加订阅
} }
} }

View File

@ -18,7 +18,7 @@ import javax.sip.ResponseEvent;
import javax.sip.message.Response; import javax.sip.message.Response;
/** /**
* @Description: 平台心跳超时事件 * @description: 平台心跳超时事件
* @author: panll * @author: panll
* @date: 2020年11月5日 10:00 * @date: 2020年11月5日 10:00
*/ */
@ -66,6 +66,7 @@ public class PlatformKeepaliveExpireEventLister implements ApplicationListener<P
storager.updateParentPlatformStatus(event.getPlatformGbID(), false); storager.updateParentPlatformStatus(event.getPlatformGbID(), false);
publisher.platformNotRegisterEventPublish(event.getPlatformGbID()); publisher.platformNotRegisterEventPublish(event.getPlatformGbID());
parentPlatformCatch.setKeepAliveReply(0); parentPlatformCatch.setKeepAliveReply(0);
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
}else { }else {
// 再次发送心跳 // 再次发送心跳
String callId = sipCommanderForPlatform.keepalive(parentPlatform); String callId = sipCommanderForPlatform.keepalive(parentPlatform);
@ -75,8 +76,8 @@ public class PlatformKeepaliveExpireEventLister implements ApplicationListener<P
redisCatchStorage.updatePlatformKeepalive(parentPlatform); redisCatchStorage.updatePlatformKeepalive(parentPlatform);
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
sipSubscribe.addOkSubscribe(callId, (ResponseEvent responseEvent) ->{ sipSubscribe.addOkSubscribe(callId, (SipSubscribe.EventResult eventResult) ->{
if (responseEvent.getResponse().getStatusCode() == Response.OK) { if (eventResult.statusCode == Response.OK) {
// 收到心跳响应信息, // 收到心跳响应信息,
parentPlatformCatch.setKeepAliveReply(0); parentPlatformCatch.setKeepAliveReply(0);
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);

View File

@ -19,7 +19,7 @@ import org.springframework.stereotype.Component;
import java.util.*; import java.util.*;
/** /**
* @Description: 平台未注册事件,来源有二: * @description: 平台未注册事件,来源有二:
* 1平台新添加 * 1平台新添加
* 2平台心跳超时 * 2平台心跳超时
* @author: panll * @author: panll
@ -100,6 +100,6 @@ public class PlatformNotRegisterEventLister implements ApplicationListener<Platf
logger.info("再次向平台注册平台国标ID" + event.getPlatformGbID()); logger.info("再次向平台注册平台国标ID" + event.getPlatformGbID());
sipCommanderFroPlatform.register(parentPlatform, null, okEvent); sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
} }
}, config.getRegisterTimeInterval(), config.getRegisterTimeInterval());//十五秒后再次发起注册 }, config.getRegisterTimeInterval()* 1000, config.getRegisterTimeInterval()* 1000);//十五秒后再次发起注册
} }
} }

View File

@ -15,7 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* @Description:视频流session管理器管理视频预览预览回放的通信句柄 * @description:视频流session管理器管理视频预览预览回放的通信句柄
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月13日 下午4:03:02 * @date: 2020年5月13日 下午4:03:02
*/ */

View File

@ -0,0 +1,6 @@
package com.genersoft.iot.vmp.gb28181.transmit;
import javax.sip.SipListener;
public interface ISIPProcessorObserver extends SipListener {
}

View File

@ -1,243 +0,0 @@
package com.genersoft.iot.vmp.gb28181.transmit;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.SipProvider;
import javax.sip.header.CSeqHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.service.IDeviceAlarmService;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
import com.genersoft.iot.vmp.service.IPlayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.AckRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.ByeRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.CancelRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.InviteRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.NotifyRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.OtherRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.SubscribeRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.ByeResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.CancelResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.InviteResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.OtherResponseProcessor;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
/**
* @Description: SIP信令处理分配
* @author: swwheihei
* @date: 2020年5月3日 下午4:24:37
*/
@Component
public class SIPProcessorFactory {
// private final static Logger logger = LoggerFactory.getLogger(SIPProcessorFactory.class);
@Autowired
private SipConfig sipConfig;
@Autowired
private RegisterLogicHandler handler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private EventPublisher publisher;
@Autowired
private SIPCommander cmder;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private IDeviceAlarmService deviceAlarmService;
@Autowired
private RedisUtil redis;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Autowired
private InviteResponseProcessor inviteResponseProcessor;
@Autowired
private ByeResponseProcessor byeResponseProcessor;
@Autowired
private CancelResponseProcessor cancelResponseProcessor;
@Autowired
@Lazy
private RegisterResponseProcessor registerResponseProcessor;
@Autowired
private OtherResponseProcessor otherResponseProcessor;
@Autowired
private IPlayService playService;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private IMediaServerService mediaServerService;
// 这里使用注解会导致循环依赖注入暂用springBean
private SipProvider tcpSipProvider;
// 这里使用注解会导致循环依赖注入暂用springBean
private SipProvider udpSipProvider;
public ISIPRequestProcessor createRequestProcessor(RequestEvent evt) {
Request request = evt.getRequest();
String method = request.getMethod();
// logger.info("接收到消息:"+request.getMethod());
// sipSubscribe.getSubscribe(evt.getServerTransaction().getBranchId()).response(evt);
if (Request.INVITE.equals(method)) {
InviteRequestProcessor processor = new InviteRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setCmder(cmder);
processor.setCmderFroPlatform(cmderFroPlatform);
processor.setPlayService(playService);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
processor.setMediaServerService(mediaServerService);
return processor;
} else if (Request.REGISTER.equals(method)) {
RegisterRequestProcessor processor = new RegisterRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setHandler(handler);
processor.setPublisher(publisher);
processor.setSipConfig(sipConfig);
processor.setVideoManagerStorager(storager);
return processor;
} else if (Request.SUBSCRIBE.equals(method)) {
SubscribeRequestProcessor processor = new SubscribeRequestProcessor();
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setRequestEvent(evt);
return processor;
} else if (Request.ACK.equals(method)) {
AckRequestProcessor processor = new AckRequestProcessor();
processor.setRequestEvent(evt);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
processor.setMediaServerService(mediaServerService);
return processor;
} else if (Request.BYE.equals(method)) {
ByeRequestProcessor processor = new ByeRequestProcessor();
processor.setRequestEvent(evt);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setStorager(storager);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
processor.setSIPCommander(cmder);
processor.setMediaServerService(mediaServerService);
return processor;
} else if (Request.CANCEL.equals(method)) {
CancelRequestProcessor processor = new CancelRequestProcessor();
processor.setRequestEvent(evt);
return processor;
} else if (Request.MESSAGE.equals(method)) {
MessageRequestProcessor processor = new MessageRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setPublisher(publisher);
processor.setRedis(redis);
processor.setDeferredResultHolder(deferredResultHolder);
processor.setOffLineDetector(offLineDetector);
processor.setCmder(cmder);
processor.setCmderFroPlatform(cmderFroPlatform);
processor.setDeviceAlarmService(deviceAlarmService);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
return processor;
} else if (Request.NOTIFY.equalsIgnoreCase(method)) {
NotifyRequestProcessor processor = new NotifyRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setPublisher(publisher);
processor.setRedis(redis);
processor.setDeferredResultHolder(deferredResultHolder);
processor.setOffLineDetector(offLineDetector);
processor.setCmder(cmder);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
return processor;
} else {
OtherRequestProcessor processor = new OtherRequestProcessor();
processor.setRequestEvent(evt);
return processor;
}
}
public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) {
Response response = evt.getResponse();
CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
String method = cseqHeader.getMethod();
if(Request.INVITE.equals(method)){
return inviteResponseProcessor;
} else if (Request.BYE.equals(method)) {
return byeResponseProcessor;
} else if (Request.CANCEL.equals(method)) {
return cancelResponseProcessor;
}else if (Request.REGISTER.equals(method)) {
return registerResponseProcessor;
} else {
return otherResponseProcessor;
}
}
private SipProvider getTcpSipProvider() {
if (tcpSipProvider == null) {
tcpSipProvider = (SipProvider) SpringBeanFactory.getBean("tcpSipProvider");
}
return tcpSipProvider;
}
private SipProvider getUdpSipProvider() {
if (udpSipProvider == null) {
udpSipProvider = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
}
return udpSipProvider;
}
}

View File

@ -0,0 +1,162 @@
package com.genersoft.iot.vmp.gb28181.transmit;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.response.ISIPResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.timeout.ITimeoutProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import javax.sip.*;
import javax.sip.header.CSeqHeader;
import javax.sip.header.CallIdHeader;
import javax.sip.message.Response;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @description: SIP信令处理类观察者
* @author: panlinlin
* @date: 2021年11月5日 下午1532
*/
@Component
public class SIPProcessorObserver implements ISIPProcessorObserver {
private final static Logger logger = LoggerFactory.getLogger(SIPProcessorObserver.class);
private static Map<String, ISIPRequestProcessor> requestProcessorMap = new ConcurrentHashMap<>();
private static Map<String, ISIPResponseProcessor> responseProcessorMap = new ConcurrentHashMap<>();
private static ITimeoutProcessor timeoutProcessor;
@Autowired
private SipSubscribe sipSubscribe;
// @Autowired
// @Qualifier(value = "taskExecutor")
// private ThreadPoolTaskExecutor poolTaskExecutor;
/**
* 添加 request订阅
* @param method 方法名
* @param processor 处理程序
*/
public void addRequestProcessor(String method, ISIPRequestProcessor processor) {
requestProcessorMap.put(method, processor);
}
/**
* 添加 response订阅
* @param method 方法名
* @param processor 处理程序
*/
public void addResponseProcessor(String method, ISIPResponseProcessor processor) {
responseProcessorMap.put(method, processor);
}
/**
* 添加 超时事件订阅
* @param processor 处理程序
*/
public void addTimeoutProcessor(ITimeoutProcessor processor) {
this.timeoutProcessor = processor;
}
/**
* 分发RequestEvent事件
* @param requestEvent RequestEvent事件
*/
@Override
@Async
public void processRequest(RequestEvent requestEvent) {
String method = requestEvent.getRequest().getMethod();
ISIPRequestProcessor sipRequestProcessor = requestProcessorMap.get(method);
if (sipRequestProcessor == null) {
logger.warn("不支持方法{}的request", method);
return;
}
requestProcessorMap.get(method).process(requestEvent);
}
/**
* 分发ResponseEvent事件
* @param responseEvent responseEvent事件
*/
@Override
@Async
public void processResponse(ResponseEvent responseEvent) {
logger.debug(responseEvent.getResponse().toString());
Response response = responseEvent.getResponse();
logger.debug(responseEvent.getResponse().toString());
int status = response.getStatusCode();
if (((status >= 200) && (status < 300)) || status == 401) { // Success!
// ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME);
String method = cseqHeader.getMethod();
ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method);
if (sipRequestProcessor != null) {
sipRequestProcessor.process(responseEvent);
}
if (responseEvent.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) {
CallIdHeader callIdHeader = (CallIdHeader)responseEvent.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent);
subscribe.response(eventResult);
}
}
}
} else if ((status >= 100) && (status < 200)) {
// 增加其它无需回复的响应如101180等
} else {
logger.warn("接收到失败的response响应status" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/);
if (responseEvent.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) {
CallIdHeader callIdHeader = (CallIdHeader)responseEvent.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent);
subscribe.response(eventResult);
}
}
}
if (responseEvent.getDialog() != null) {
responseEvent.getDialog().delete();
}
}
}
/**
* 向超时订阅发送消息
* @param timeoutEvent timeoutEvent事件
*/
@Override
public void processTimeout(TimeoutEvent timeoutEvent) {
if(timeoutProcessor != null) {
timeoutProcessor.process(timeoutEvent);
}
}
@Override
public void processIOException(IOExceptionEvent exceptionEvent) {
}
@Override
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
}
@Override
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
CallIdHeader callId = dialogTerminatedEvent.getDialog().getCallId();
}
}

View File

@ -1,17 +1,16 @@
package com.genersoft.iot.vmp.gb28181.transmit.callback; package com.genersoft.iot.vmp.gb28181.transmit.callback;
import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
import com.genersoft.iot.vmp.gb28181.bean.RecordItem;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.RecordInfoResponseMessageHandler;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import org.slf4j.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
import com.genersoft.iot.vmp.gb28181.bean.RecordItem;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import org.slf4j.Logger;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class CheckForAllRecordsThread extends Thread { public class CheckForAllRecordsThread extends Thread {
@ -54,13 +53,11 @@ public class CheckForAllRecordsThread extends Thread {
// 自然顺序排序, 元素进行升序排列 // 自然顺序排序, 元素进行升序排列
this.recordInfo.getRecordList().sort(Comparator.naturalOrder()); this.recordInfo.getRecordList().sort(Comparator.naturalOrder());
RequestMessage msg = new RequestMessage(); RequestMessage msg = new RequestMessage();
String deviceId = recordInfo.getDeviceId(); msg.setKey(DeferredResultHolder.CALLBACK_CMD_RECORDINFO + recordInfo.getDeviceId() + recordInfo.getSn());
msg.setDeviceId(deviceId);
msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO);
msg.setData(recordInfo); msg.setData(recordInfo);
deferredResultHolder.invokeResult(msg); deferredResultHolder.invokeAllResult(msg);
logger.info("处理完成,返回结果"); logger.info("处理完成,返回结果");
MessageRequestProcessor.threadNameList.remove(cacheKey); RecordInfoResponseMessageHandler.threadNameList.remove(cacheKey);
} }
public void setRedis(RedisUtil redis) { public void setRedis(RedisUtil redis) {

View File

@ -1,6 +1,8 @@
package com.genersoft.iot.vmp.gb28181.transmit.callback; package com.genersoft.iot.vmp.gb28181.transmit.callback;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -9,7 +11,7 @@ import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult; import org.springframework.web.context.request.async.DeferredResult;
/** /**
* @Description: 异步请求处理 * @description: 异步请求处理
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 下午7:59:05 * @date: 2020年5月8日 下午7:59:05
*/ */
@ -31,12 +33,14 @@ public class DeferredResultHolder {
public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO"; public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO";
public static final String CALLBACK_CMD_PlAY = "CALLBACK_PLAY"; public static final String CALLBACK_CMD_PLAY = "CALLBACK_PLAY";
public static final String CALLBACK_CMD_PLAYBACK = "CALLBACK_PLAY";
public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD";
public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
public static final String CALLBACK_ONVIF = "CALLBACK_ONVIF";
public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION"; public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION";
public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY"; public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY";
@ -45,21 +49,72 @@ public class DeferredResultHolder {
public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST"; public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST";
private Map<String, DeferredResult> map = new ConcurrentHashMap<String, DeferredResult>(); private Map<String, Map<String, DeferredResult>> map = new ConcurrentHashMap<>();
public void put(String key, DeferredResult result) {
map.put(key, result); public void put(String key, String id, DeferredResult result) {
Map<String, DeferredResult> deferredResultMap = map.get(key);
if (deferredResultMap == null) {
deferredResultMap = new ConcurrentHashMap<>();
map.put(key, deferredResultMap);
}
deferredResultMap.put(id, result);
} }
public DeferredResult get(String key) { public DeferredResult get(String key, String id) {
return map.get(key); Map<String, DeferredResult> deferredResultMap = map.get(key);
if (deferredResultMap == null) return null;
return deferredResultMap.get(id);
} }
public boolean exist(String key, String id){
if (key == null) return false;
Map<String, DeferredResult> deferredResultMap = map.get(key);
if (id == null) {
return deferredResultMap != null;
}else {
return deferredResultMap != null && deferredResultMap.get(id) != null;
}
}
/**
* 释放单个请求
* @param msg
*/
public void invokeResult(RequestMessage msg) { public void invokeResult(RequestMessage msg) {
DeferredResult result = map.get(msg.getId()); Map<String, DeferredResult> deferredResultMap = map.get(msg.getKey());
if (deferredResultMap == null) {
return;
}
DeferredResult result = deferredResultMap.get(msg.getId());
if (result == null) { if (result == null) {
return; return;
} }
result.setResult(new ResponseEntity<>(msg.getData(),HttpStatus.OK)); result.setResult(new ResponseEntity<>(msg.getData(),HttpStatus.OK));
deferredResultMap.remove(msg.getId());
if (deferredResultMap.size() == 0) {
map.remove(msg.getKey());
}
}
/**
* 释放所有的请求
* @param msg
*/
public void invokeAllResult(RequestMessage msg) {
Map<String, DeferredResult> deferredResultMap = map.get(msg.getKey());
if (deferredResultMap == null) {
return;
}
Set<String> ids = deferredResultMap.keySet();
for (String id : ids) {
DeferredResult result = deferredResultMap.get(id);
if (result == null) {
return;
}
result.setResult(ResponseEntity.ok().body(msg.getData()));
}
map.remove(msg.getKey());
} }
} }

View File

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.gb28181.transmit.callback; package com.genersoft.iot.vmp.gb28181.transmit.callback;
/** /**
* @Description: 请求信息定义 * @description: 请求信息定义
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月8日 下午1:09:18 * @date: 2020年5月8日 下午1:09:18
*/ */
@ -9,12 +9,10 @@ public class RequestMessage {
private String id; private String id;
private String deviceId; private String key;
private String type;
private Object data; private Object data;
public String getId() { public String getId() {
return id; return id;
} }
@ -23,22 +21,12 @@ public class RequestMessage {
this.id = id; this.id = id;
} }
public String getDeviceId() { public void setKey(String key) {
return deviceId; this.key = key;
} }
public void setDeviceId(String deviceId) { public String getKey() {
this.deviceId = deviceId; return key;
this.id = type + deviceId;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
this.id = type + deviceId;
} }
public Object getData() { public Object getData() {

View File

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.gb28181.transmit.cmd; package com.genersoft.iot.vmp.gb28181.transmit.cmd;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
@ -7,7 +8,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.service.bean.SSRCInfo;
/** /**
* @Description:设备能力接口用于定义设备的控制查询能力 * @description:设备能力接口用于定义设备的控制查询能力
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月3日 下午9:16:34 * @date: 2020年5月3日 下午9:16:34
*/ */
@ -121,6 +122,26 @@ public interface ISIPCommander {
void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent); void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent);
void streamByeCmd(String deviceId, String channelId); void streamByeCmd(String deviceId, String channelId);
/**
* 回放暂停
*/
void playPauseCmd(Device device, StreamInfo streamInfo);
/**
* 回放恢复
*/
void playResumeCmd(Device device, StreamInfo streamInfo);
/**
* 回放拖动播放
*/
void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime);
/**
* 回放倍速播放
*/
void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed);
/** /**
* 语音广播 * 语音广播
* *
@ -235,8 +256,9 @@ public interface ISIPCommander {
* @param device 视频设备 * @param device 视频设备
* @param startTime 开始时间,格式要求yyyy-MM-dd HH:mm:ss * @param startTime 开始时间,格式要求yyyy-MM-dd HH:mm:ss
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss * @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
* @param sn
*/ */
boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime); boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, SipSubscribe.Event errorEvent);
/** /**
* 查询报警信息 * 查询报警信息
@ -299,4 +321,11 @@ public interface ISIPCommander {
* @return true = 命令发送成功 * @return true = 命令发送成功
*/ */
boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime); boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime);
/**
* 订阅取消订阅目录信息
* @param device 视频设备
* @return true = 命令发送成功
*/
boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent);
} }

View File

@ -19,7 +19,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
* @Description: 平台命令request创造器 TODO 冗余代码太多待优化 * @description: 平台命令request创造器 TODO 冗余代码太多待优化
* @author: panll * @author: panll
* @date: 2020年5月6日 上午9:29:02 * @date: 2020年5月6日 上午9:29:02
*/ */

View File

@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
import java.text.ParseException; import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import javax.sip.Dialog;
import javax.sip.InvalidArgumentException; import javax.sip.InvalidArgumentException;
import javax.sip.PeerUnavailableException; import javax.sip.PeerUnavailableException;
import javax.sip.SipFactory; import javax.sip.SipFactory;
@ -11,6 +12,9 @@ import javax.sip.address.SipURI;
import javax.sip.header.*; import javax.sip.header.*;
import javax.sip.message.Request; import javax.sip.message.Request;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.vmanager.gb28181.session.InfoCseqCache;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -18,7 +22,7 @@ import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
/** /**
* @Description:摄像头命令request创造器 TODO 冗余代码太多待优化 * @description:摄像头命令request创造器 TODO 冗余代码太多待优化
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月6日 上午9:29:02 * @date: 2020年5月6日 上午9:29:02
*/ */
@ -30,6 +34,9 @@ public class SIPRequestHeaderProvider {
@Autowired @Autowired
private SipFactory sipFactory; private SipFactory sipFactory;
@Autowired
private VideoStreamSessionManager streamSession;
public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null; Request request = null;
@ -99,13 +106,13 @@ public class SIPRequestHeaderProvider {
return request; return request;
} }
public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null; Request request = null;
//请求行 //请求行
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
// via // via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag); ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag);
viaHeader.setRPort(); viaHeader.setRPort();
viaHeaders.add(viaHeader); viaHeaders.add(viaHeader);
//from //from
@ -113,7 +120,7 @@ public class SIPRequestHeaderProvider {
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI); Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记否则无法创建会话无法回应ack FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记否则无法创建会话无法回应ack
//to //to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,sipConfig.getDomain()); SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, sipConfig.getDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI); Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress,null); ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress,null);
@ -127,7 +134,10 @@ public class SIPRequestHeaderProvider {
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort())); Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort()));
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort())); // Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
// Subject
SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
request.addHeader(subjectHeader);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
request.setContent(content, contentTypeHeader); request.setContent(content, contentTypeHeader);
return request; return request;
@ -207,4 +217,50 @@ public class SIPRequestHeaderProvider {
request.setContent(content, contentTypeHeader); request.setContent(content, contentTypeHeader);
return request; return request;
} }
public Request createInfoRequest(Device device, StreamInfo streamInfo, String content)
throws PeerUnavailableException, ParseException, InvalidArgumentException {
Request request = null;
Dialog dialog = streamSession.getDialog(streamInfo.getDeviceID(), streamInfo.getChannelId());
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(),
device.getHostAddress());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(),
device.getTransport(), null);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
// from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(),
sipConfig.getDomain());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, dialog.getLocalTag());
// to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(streamInfo.getChannelId(),
sipConfig.getDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, dialog.getRemoteTag());
// callid
CallIdHeader callIdHeader = dialog.getCallId();
// Forwards
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
// ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory()
.createCSeqHeader(InfoCseqCache.CSEQCACHE.get(streamInfo.getStreamId()), Request.INFO);
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,
fromHeader, toHeader, viaHeaders, maxForwards);
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
.createSipURI(sipConfig.getId(), sipConfig.getIp() + ":" + sipConfig.getPort()));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application",
"MANSRTSP");
request.setContent(content, contentTypeHeader);
return request;
}
} }

View File

@ -1,25 +1,24 @@
package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.HashSet;
import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.header.CallIdHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Request;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
import com.genersoft.iot.vmp.media.zlm.*;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.gb28181.session.InfoCseqCache;
import gov.nist.javax.sip.SipProviderImpl; import gov.nist.javax.sip.SipProviderImpl;
import gov.nist.javax.sip.SipStackImpl; import gov.nist.javax.sip.SipStackImpl;
import gov.nist.javax.sip.message.SIPRequest; import gov.nist.javax.sip.message.SIPRequest;
@ -29,20 +28,20 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.header.CallIdHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Request;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.HashSet;
/** /**
* @Description:设备能力接口用于定义设备的控制查询能力 * @description:设备能力接口用于定义设备的控制查询能力
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月3日 下午9:22:48 * @date: 2020年5月3日 下午9:22:48
*/ */
@ -55,12 +54,10 @@ public class SIPCommander implements ISIPCommander {
@Autowired @Autowired
private SipConfig sipConfig; private SipConfig sipConfig;
@Lazy
@Autowired @Autowired
@Qualifier(value="tcpSipProvider") @Qualifier(value="tcpSipProvider")
private SipProviderImpl tcpSipProvider; private SipProviderImpl tcpSipProvider;
@Lazy
@Autowired @Autowired
@Qualifier(value="udpSipProvider") @Qualifier(value="udpSipProvider")
private SipProviderImpl udpSipProvider; private SipProviderImpl udpSipProvider;
@ -89,11 +86,6 @@ public class SIPCommander implements ISIPCommander {
@Autowired @Autowired
private IMediaServerService mediaServerService; private IMediaServerService mediaServerService;
private SIPDialog dialog;
public SipConfig getSipConfig() {
return sipConfig;
}
/** /**
* 云台方向放控制使用配置文件中的默认镜头移动速度 * 云台方向放控制使用配置文件中的默认镜头移动速度
@ -361,7 +353,7 @@ public class SIPCommander implements ISIPCommander {
// //
StringBuffer content = new StringBuffer(200); StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n"); content.append("v=0\r\n");
content.append("o="+"00000"+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n"); content.append("o="+ sipConfig.getId()+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
content.append("s=Play\r\n"); content.append("s=Play\r\n");
content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n"); content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
content.append("t=0 0\r\n"); content.append("t=0 0\r\n");
@ -427,8 +419,8 @@ public class SIPCommander implements ISIPCommander {
mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc()); mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc());
errorEvent.response(e); errorEvent.response(e);
}), e ->{ }), e ->{
streamSession.put(device.getDeviceId(), channelId ,ssrcInfo.getSsrc(), finalStreamId, mediaServerItem.getId(),e.getClientTransaction()); streamSession.put(device.getDeviceId(), channelId ,ssrcInfo.getSsrc(), finalStreamId, mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction());
streamSession.put(device.getDeviceId(), channelId , e.getDialog()); streamSession.put(device.getDeviceId(), channelId , e.dialog);
}); });
@ -468,7 +460,7 @@ public class SIPCommander implements ISIPCommander {
StringBuffer content = new StringBuffer(200); StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n"); content.append("v=0\r\n");
content.append("o="+sipConfig.getId()+" 0 0 IN IP4 "+sipConfig.getIp()+"\r\n"); content.append("o="+sipConfig.getId()+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
content.append("s=Playback\r\n"); content.append("s=Playback\r\n");
content.append("u="+channelId+":0\r\n"); content.append("u="+channelId+":0\r\n");
content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
@ -532,12 +524,12 @@ public class SIPCommander implements ISIPCommander {
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId(); : udpSipProvider.getNewCallId();
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader); Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
transmitRequest(device, request, errorEvent, okEvent -> { transmitRequest(device, request, errorEvent, okEvent -> {
Dialog dialog = okEvent.getClientTransaction().getDialog(); ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), okEvent.getClientTransaction()); streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), responseEvent.getClientTransaction());
streamSession.put(device.getDeviceId(), channelId, dialog); streamSession.put(device.getDeviceId(), channelId, okEvent.dialog);
}); });
} catch ( SipException | ParseException | InvalidArgumentException e) { } catch ( SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace(); e.printStackTrace();
@ -575,7 +567,7 @@ public class SIPCommander implements ISIPCommander {
StringBuffer content = new StringBuffer(200); StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n"); content.append("v=0\r\n");
content.append("o="+sipConfig.getId()+" 0 0 IN IP4 "+sipConfig.getIp()+"\r\n"); content.append("o="+sipConfig.getId()+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
content.append("s=Download\r\n"); content.append("s=Download\r\n");
content.append("u="+channelId+":0\r\n"); content.append("u="+channelId+":0\r\n");
content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
@ -640,7 +632,7 @@ public class SIPCommander implements ISIPCommander {
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId(); : udpSipProvider.getNewCallId();
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader); Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
ClientTransaction transaction = transmitRequest(device, request, errorEvent); ClientTransaction transaction = transmitRequest(device, request, errorEvent);
streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), transaction); streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), transaction);
@ -667,6 +659,10 @@ public class SIPCommander implements ISIPCommander {
ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId); ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId);
if (transaction == null) { if (transaction == null) {
logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId); logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>();
if (okEvent != null) {
okEvent.response(eventResult);
}
return; return;
} }
SIPDialog dialog = streamSession.getDialog(deviceId, channelId); SIPDialog dialog = streamSession.getDialog(deviceId, channelId);
@ -1200,14 +1196,15 @@ public class SIPCommander implements ISIPCommander {
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss * @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
*/ */
@Override @Override
public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime) { public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, SipSubscribe.Event errorEvent) {
try { try {
StringBuffer recordInfoXml = new StringBuffer(200); StringBuffer recordInfoXml = new StringBuffer(200);
recordInfoXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n"); recordInfoXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
recordInfoXml.append("<Query>\r\n"); recordInfoXml.append("<Query>\r\n");
recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n"); recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");
recordInfoXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n"); recordInfoXml.append("<SN>" + sn + "</SN>\r\n");
recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n"); recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n"); recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
@ -1224,7 +1221,7 @@ public class SIPCommander implements ISIPCommander {
Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),
"z9hG4bK-ViaRecordInfo-" + tm, "fromRec" + tm, null, callIdHeader); "z9hG4bK-ViaRecordInfo-" + tm, "fromRec" + tm, null, callIdHeader);
transmitRequest(device, request); transmitRequest(device, request, errorEvent);
} catch (SipException | ParseException | InvalidArgumentException e) { } catch (SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace(); e.printStackTrace();
return false; return false;
@ -1486,6 +1483,33 @@ public class SIPCommander implements ISIPCommander {
} }
} }
@Override
public boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
try {
StringBuffer cmdXml = new StringBuffer(200);
cmdXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
cmdXml.append("<Query>\r\n");
cmdXml.append("<CmdType>Catalog</CmdType>\r\n");
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
cmdXml.append("</Query>\r\n");
String tm = Long.toString(System.currentTimeMillis());
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId();
Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" , callIdHeader);
transmitRequest(device, request, errorEvent, okEvent);
return true;
} catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
e.printStackTrace();
return false;
}
}
private ClientTransaction transmitRequest(Device device, Request request) throws SipException { private ClientTransaction transmitRequest(Device device, Request request) throws SipException {
return transmitRequest(device, request, null, null); return transmitRequest(device, request, null, null);
@ -1506,14 +1530,127 @@ public class SIPCommander implements ISIPCommander {
CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME); CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
// 添加错误订阅 // 添加错误订阅
if (errorEvent != null) { if (errorEvent != null) {
sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), errorEvent); sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
errorEvent.response(eventResult);
sipSubscribe.removeErrorSubscribe(eventResult.callId);
}));
} }
// 添加订阅 // 添加订阅
if (okEvent != null) { if (okEvent != null) {
sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent); sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult ->{
okEvent.response(eventResult);
sipSubscribe.removeOkSubscribe(eventResult.callId);
});
} }
clientTransaction.sendRequest(); clientTransaction.sendRequest();
return clientTransaction; return clientTransaction;
} }
/**
* 回放暂停
*/
@Override
public void playPauseCmd(Device device, StreamInfo streamInfo) {
try {
StringBuffer content = new StringBuffer(200);
content.append("PAUSE RTSP/1.0\r\n");
content.append("CSeq: " + InfoCseqCache.CSEQCACHE.get(streamInfo.getStreamId()) + "\r\n");
content.append("PauseTime: now\r\n");
Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
logger.info(request.toString());
ClientTransaction clientTransaction = null;
if ("TCP".equals(device.getTransport())) {
clientTransaction = tcpSipProvider.getNewClientTransaction(request);
} else if ("UDP".equals(device.getTransport())) {
clientTransaction = udpSipProvider.getNewClientTransaction(request);
}
if (clientTransaction != null) {
clientTransaction.sendRequest();
}
} catch (SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
}
}
/**
* 回放恢复
*/
@Override
public void playResumeCmd(Device device, StreamInfo streamInfo) {
try {
StringBuffer content = new StringBuffer(200);
content.append("PLAY RTSP/1.0\r\n");
content.append("CSeq: " + InfoCseqCache.CSEQCACHE.get(streamInfo.getStreamId()) + "\r\n");
content.append("Range: npt=now-\r\n");
Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
logger.info(request.toString());
ClientTransaction clientTransaction = null;
if ("TCP".equals(device.getTransport())) {
clientTransaction = tcpSipProvider.getNewClientTransaction(request);
} else if ("UDP".equals(device.getTransport())) {
clientTransaction = udpSipProvider.getNewClientTransaction(request);
}
clientTransaction.sendRequest();
} catch (SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
}
}
/**
* 回放拖动播放
*/
@Override
public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) {
try {
StringBuffer content = new StringBuffer(200);
content.append("PLAY RTSP/1.0\r\n");
content.append("CSeq: " + InfoCseqCache.CSEQCACHE.get(streamInfo.getStreamId()) + "\r\n");
content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n");
Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
logger.info(request.toString());
ClientTransaction clientTransaction = null;
if ("TCP".equals(device.getTransport())) {
clientTransaction = tcpSipProvider.getNewClientTransaction(request);
} else if ("UDP".equals(device.getTransport())) {
clientTransaction = udpSipProvider.getNewClientTransaction(request);
}
clientTransaction.sendRequest();
} catch (SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
}
}
/**
* 回放倍速播放
*/
@Override
public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) {
try {
StringBuffer content = new StringBuffer(200);
content.append("PLAY RTSP/1.0\r\n");
content.append("CSeq: " + InfoCseqCache.CSEQCACHE.get(streamInfo.getStreamId()) + "\r\n");
content.append("Scale: " + String.format("%.1f",speed) + "\r\n");
Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
logger.info(request.toString());
ClientTransaction clientTransaction = null;
if ("TCP".equals(device.getTransport())) {
clientTransaction = tcpSipProvider.getNewClientTransaction(request);
} else if ("UDP".equals(device.getTransport())) {
clientTransaction = udpSipProvider.getNewClientTransaction(request);
}
clientTransaction.sendRequest();
} catch (SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
}
}
} }

View File

@ -100,7 +100,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
if (event != null) { if (event != null) {
logger.info("向上级平台 [ {} ] 注册发上错误: {} ", logger.info("向上级平台 [ {} ] 注册发上错误: {} ",
parentPlatform.getServerGBId(), parentPlatform.getServerGBId(),
event.getResponse().getReasonPhrase()); event.msg);
} }
if (errorEvent != null ) { if (errorEvent != null ) {
errorEvent.response(event); errorEvent.response(event);

View File

@ -0,0 +1,14 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request;
import javax.sip.RequestEvent;
/**
* @description: 对SIP事件进行处理包括request response timeout ioException, transactionTerminated,dialogTerminated
* @author: panlinlin
* @date: 2021年11月5日 1547
*/
public interface ISIPRequestProcessor {
void process(RequestEvent event);
}

View File

@ -0,0 +1,23 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request;
import gov.nist.javax.sip.SipProviderImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* @description:处理接收IPCamera发来的SIP协议请求消息
* @author: songww
* @date: 2020年5月3日 下午4:42:22
*/
public abstract class SIPRequestProcessorAbstract {
@Autowired
@Qualifier(value="tcpSipProvider")
private SipProviderImpl tcpSipProvider;
@Autowired
@Qualifier(value="udpSipProvider")
private SipProviderImpl udpSipProvider;
}

View File

@ -0,0 +1,179 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request;
import gov.nist.javax.sip.SipProviderImpl;
import gov.nist.javax.sip.SipStackImpl;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.stack.SIPServerTransaction;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.sip.*;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.HeaderFactory;
import javax.sip.header.ViaHeader;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.io.ByteArrayInputStream;
import java.text.ParseException;
/**
* @description:处理接收IPCamera发来的SIP协议请求消息
* @author: songww
* @date: 2020年5月3日 下午4:42:22
*/
public abstract class SIPRequestProcessorParent {
private final static Logger logger = LoggerFactory.getLogger(SIPRequestProcessorParent.class);
@Autowired
@Qualifier(value="tcpSipProvider")
private SipProviderImpl tcpSipProvider;
@Autowired
@Qualifier(value="udpSipProvider")
private SipProviderImpl udpSipProvider;
/**
* 根据 RequestEvent 获取 ServerTransaction
* @param evt
* @return
*/
public ServerTransaction getServerTransaction(RequestEvent evt) {
Request request = evt.getRequest();
ServerTransaction serverTransaction = evt.getServerTransaction();
// 判断TCP还是UDP
boolean isTcp = false;
ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
String transport = reqViaHeader.getTransport();
if (transport.equals("TCP")) {
isTcp = true;
}
if (serverTransaction == null) {
try {
if (isTcp) {
SipStackImpl stack = (SipStackImpl)tcpSipProvider.getSipStack();
serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true);
if (serverTransaction == null) {
serverTransaction = tcpSipProvider.getNewServerTransaction(request);
}
} else {
SipStackImpl stack = (SipStackImpl)udpSipProvider.getSipStack();
serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true);
if (serverTransaction == null) {
serverTransaction = udpSipProvider.getNewServerTransaction(request);
}
}
} catch (TransactionAlreadyExistsException e) {
logger.error(e.getMessage());
} catch (TransactionUnavailableException e) {
logger.error(e.getMessage());
}
}
return serverTransaction;
}
public AddressFactory getAddressFactory() {
try {
return SipFactory.getInstance().createAddressFactory();
} catch (PeerUnavailableException e) {
e.printStackTrace();
}
return null;
}
public HeaderFactory getHeaderFactory() {
try {
return SipFactory.getInstance().createHeaderFactory();
} catch (PeerUnavailableException e) {
e.printStackTrace();
}
return null;
}
public MessageFactory getMessageFactory() {
try {
return SipFactory.getInstance().createMessageFactory();
} catch (PeerUnavailableException e) {
e.printStackTrace();
}
return null;
}
/***
* 回复状态码
* 100 trying
* 200 OK
* 400
* 404
* @param evt
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
public void responseAck(RequestEvent evt, int statusCode) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
ServerTransaction serverTransaction = getServerTransaction(evt);
serverTransaction.sendResponse(response);
if (statusCode >= 200 && !"NOTIFY".equals(evt.getRequest().getMethod())) {
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
}
}
public void responseAck(RequestEvent evt, int statusCode, String msg) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
response.setReasonPhrase(msg);
ServerTransaction serverTransaction = getServerTransaction(evt);
serverTransaction.sendResponse(response);
if (statusCode >= 200 && !"NOTIFY".equals(evt.getRequest().getMethod())) {
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
}
}
/**
* 回复带sdp的200
* @param evt
* @param sdp
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
public void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
SipFactory sipFactory = SipFactory.getInstance();
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
response.setContent(sdp, contentTypeHeader);
SipURI sipURI = (SipURI)evt.getRequest().getRequestURI();
Address concatAddress = sipFactory.createAddressFactory().createAddress(
sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost()+":"+sipURI.getPort()
));
response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
getServerTransaction(evt).sendResponse(response);
}
public Element getRootElement(RequestEvent evt) throws DocumentException {
return getRootElement(evt, "gb2312");
}
public Element getRootElement(RequestEvent evt, String charset) throws DocumentException {
if (charset == null) charset = "gb2312";
Request request = evt.getRequest();
SAXReader reader = new SAXReader();
reader.setEncoding(charset);
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
return xml.getRootElement();
}
}

View File

@ -1,142 +1,123 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import java.util.HashMap; import com.genersoft.iot.vmp.common.StreamInfo;
import java.util.Map; import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import javax.sip.*; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import javax.sip.address.SipURI; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import javax.sip.header.FromHeader; import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import javax.sip.header.HeaderAddress; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import javax.sip.header.ToHeader; import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.common.StreamInfo; import org.slf4j.Logger;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; import org.slf4j.LoggerFactory;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import org.springframework.beans.factory.InitializingBean;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; import org.springframework.beans.factory.annotation.Autowired;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import javax.sip.Dialog;
import org.slf4j.Logger; import javax.sip.DialogState;
import org.slf4j.LoggerFactory; import javax.sip.RequestEvent;
import javax.sip.address.SipURI;
/** import javax.sip.header.FromHeader;
* @Description:ACK请求处理器 import javax.sip.header.HeaderAddress;
* @author: swwheihei import javax.sip.header.ToHeader;
* @date: 2020年5月3日 下午5:31:45 import java.util.HashMap;
*/ import java.util.Map;
public class AckRequestProcessor extends SIPRequestAbstractProcessor {
/**
private Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class); * SIP命令类型 ACK请求
*/
private IRedisCatchStorage redisCatchStorage; @Component
public class AckRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private ZLMRTPServerFactory zlmrtpServerFactory;
private Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class);
private IMediaServerService mediaServerService; private String method = "ACK";
/** @Autowired
* 处理 ACK请求 private SIPProcessorObserver sipProcessorObserver;
*
* @param evt @Override
*/ public void afterPropertiesSet() throws Exception {
@Override // 添加消息处理的订阅
public void process(RequestEvent evt) { sipProcessorObserver.addRequestProcessor(method, this);
//Request request = evt.getRequest(); }
Dialog dialog = evt.getDialog();
if (dialog == null) return; @Autowired
//DialogState state = dialog.getState(); private IRedisCatchStorage redisCatchStorage;
if (/*request.getMecodewwthod().equals(Request.INVITE) &&*/ dialog.getState()== DialogState.CONFIRMED) {
String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); @Autowired
String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); private ZLMRTPServerFactory zlmrtpServerFactory;
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
String is_Udp = sendRtpItem.isTcp() ? "0" : "1"; @Autowired
String deviceId = sendRtpItem.getDeviceId(); private IMediaServerService mediaServerService;
StreamInfo streamInfo = null;
if (deviceId == null) {
streamInfo = new StreamInfo(); /**
streamInfo.setApp(sendRtpItem.getApp()); * 处理 ACK请求
streamInfo.setStreamId(sendRtpItem.getStreamId()); *
}else { * @param evt
streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); */
sendRtpItem.setStreamId(streamInfo.getStreamId()); @Override
streamInfo.setApp("rtp"); public void process(RequestEvent evt) {
} Dialog dialog = evt.getDialog();
if (dialog == null) return;
redisCatchStorage.updateSendRTPSever(sendRtpItem); if (dialog.getState()== DialogState.CONFIRMED) {
logger.info(platformGbId); String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
logger.info(channelId); String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
Map<String, Object> param = new HashMap<>(); SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
param.put("vhost","__defaultVhost__"); String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
param.put("app",streamInfo.getApp()); String deviceId = sendRtpItem.getDeviceId();
param.put("stream",streamInfo.getStreamId()); StreamInfo streamInfo = null;
param.put("ssrc", sendRtpItem.getSsrc()); if (deviceId == null) {
param.put("dst_url",sendRtpItem.getIp()); streamInfo = new StreamInfo();
param.put("dst_port", sendRtpItem.getPort()); streamInfo.setApp(sendRtpItem.getApp());
param.put("is_udp", is_Udp); streamInfo.setStreamId(sendRtpItem.getStreamId());
//param.put ("src_port", sendRtpItem.getLocalPort()); }else {
// 设备推流查询成功后才能转推 streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
boolean rtpPushed = false; sendRtpItem.setStreamId(streamInfo.getStreamId());
long startTime = System.currentTimeMillis(); streamInfo.setApp("rtp");
while (!rtpPushed) { }
try {
if (System.currentTimeMillis() - startTime < 30 * 1000) { redisCatchStorage.updateSendRTPSever(sendRtpItem);
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); logger.info(platformGbId);
if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) { logger.info(channelId);
rtpPushed = true; Map<String, Object> param = new HashMap<>();
logger.info("已获取设备推流[{}/{}],开始向上级推流[{}:{}]", param.put("vhost","__defaultVhost__");
streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort()); param.put("app",streamInfo.getApp());
zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); param.put("stream",streamInfo.getStreamId());
} else { param.put("ssrc", sendRtpItem.getSsrc());
logger.info("等待设备推流[{}/{}].......", param.put("dst_url",sendRtpItem.getIp());
streamInfo.getApp() ,streamInfo.getStreamId()); param.put("dst_port", sendRtpItem.getPort());
Thread.sleep(1000); param.put("is_udp", is_Udp);
continue; //param.put ("src_port", sendRtpItem.getLocalPort());
} // 设备推流查询成功后才能转推
} else { boolean rtpPushed = false;
rtpPushed = true; long startTime = System.currentTimeMillis();
logger.info("设备推流[{}/{}]超时,终止向上级推流", while (!rtpPushed) {
streamInfo.getApp() ,streamInfo.getStreamId()); try {
} if (System.currentTimeMillis() - startTime < 30 * 1000) {
} catch (InterruptedException e) { MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
e.printStackTrace(); if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) {
} rtpPushed = true;
} logger.info("已获取设备推流[{}/{}],开始向上级推流[{}:{}]",
} streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort());
// try { zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
// Request ackRequest = null; } else {
// CSeq csReq = (CSeq) request.getHeader(CSeq.NAME); logger.info("等待设备推流[{}/{}].......",
// ackRequest = dialog.createAck(csReq.getSeqNumber()); streamInfo.getApp() ,streamInfo.getStreamId());
// dialog.sendAck(ackRequest); Thread.sleep(1000);
// logger.info("send ack to callee:" + ackRequest.toString()); continue;
// } catch (SipException e) { }
// e.printStackTrace(); } else {
// } catch (InvalidArgumentException e) { rtpPushed = true;
// e.printStackTrace(); logger.info("设备推流[{}/{}]超时,终止向上级推流",
// } streamInfo.getApp() ,streamInfo.getStreamId());
}
} } catch (InterruptedException e) {
e.printStackTrace();
public IRedisCatchStorage getRedisCatchStorage() { }
return redisCatchStorage; }
} }
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) { }
this.redisCatchStorage = redisCatchStorage;
}
public ZLMRTPServerFactory getZlmrtpServerFactory() {
return zlmrtpServerFactory;
}
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
this.zlmrtpServerFactory = zlmrtpServerFactory;
}
public IMediaServerService getMediaServerService() {
return mediaServerService;
}
public void setMediaServerService(IMediaServerService mediaServerService) {
this.mediaServerService = mediaServerService;
}
}

View File

@ -1,150 +1,114 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import javax.sip.*; import com.genersoft.iot.vmp.common.StreamInfo;
import javax.sip.address.SipURI; import com.genersoft.iot.vmp.gb28181.bean.Device;
import javax.sip.header.FromHeader; import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import javax.sip.header.HeaderAddress; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import javax.sip.header.ToHeader; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import javax.sip.message.Response; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; import org.slf4j.Logger;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import org.slf4j.LoggerFactory;
import com.genersoft.iot.vmp.service.IMediaServerService; import org.springframework.beans.factory.InitializingBean;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import org.springframework.beans.factory.annotation.Autowired;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.sip.*;
import javax.sip.address.SipURI;
import java.text.ParseException; import javax.sip.header.FromHeader;
import java.util.HashMap; import javax.sip.header.HeaderAddress;
import java.util.Map; import javax.sip.header.ToHeader;
import javax.sip.message.Response;
/** import java.text.ParseException;
* @Description: BYE请求处理器 import java.util.HashMap;
* @author: lawrencehj import java.util.Map;
* @date: 2021年3月9日
*/ /**
public class ByeRequestProcessor extends SIPRequestAbstractProcessor { * SIP命令类型 BYE请求
*/
private Logger logger = LoggerFactory.getLogger(ByeRequestProcessor.class); @Component
public class ByeRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private ISIPCommander cmder;
private final Logger logger = LoggerFactory.getLogger(ByeRequestProcessor.class);
private IRedisCatchStorage redisCatchStorage; private final String method = "BYE";
private IVideoManagerStorager storager; @Autowired
private ISIPCommander cmder;
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private IMediaServerService mediaServerService; private IRedisCatchStorage redisCatchStorage;
/** @Autowired
* 处理BYE请求 private IVideoManagerStorager storager;
* @param evt
*/ @Autowired
@Override private ZLMRTPServerFactory zlmrtpServerFactory;
public void process(RequestEvent evt) {
try { @Autowired
responseAck(evt); private IMediaServerService mediaServerService;
Dialog dialog = evt.getDialog();
if (dialog == null) return; @Autowired
if (dialog.getState().equals(DialogState.TERMINATED)) { private SIPProcessorObserver sipProcessorObserver;
String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); @Override
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId); public void afterPropertiesSet() throws Exception {
logger.info("收到bye, [{}/{}]", platformGbId, channelId); // 添加消息处理的订阅
if (sendRtpItem != null){ sipProcessorObserver.addRequestProcessor(method, this);
String streamId = sendRtpItem.getStreamId(); }
Map<String, Object> param = new HashMap<>();
param.put("vhost","__defaultVhost__"); /**
param.put("app",sendRtpItem.getApp()); * 处理BYE请求
param.put("stream",streamId); * @param evt
param.put("ssrc",sendRtpItem.getSsrc()); */
logger.info("停止向上级推流:" + streamId); @Override
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); public void process(RequestEvent evt) {
zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); try {
redisCatchStorage.deleteSendRTPServer(platformGbId, channelId); responseAck(evt, Response.OK);
if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) { Dialog dialog = evt.getDialog();
logger.info(streamId + "无其它观看者,通知设备停止推流"); if (dialog == null) return;
cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId); if (dialog.getState().equals(DialogState.TERMINATED)) {
} String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
} String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
// 可能是设备主动停止 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
Device device = storager.queryVideoDeviceByChannelId(platformGbId); logger.info("收到bye, [{}/{}]", platformGbId, channelId);
if (device != null) { if (sendRtpItem != null){
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId); String streamId = sendRtpItem.getStreamId();
if (streamInfo != null) { Map<String, Object> param = new HashMap<>();
redisCatchStorage.stopPlay(streamInfo); param.put("vhost","__defaultVhost__");
} param.put("app",sendRtpItem.getApp());
storager.stopPlay(device.getDeviceId(), channelId); param.put("stream",streamId);
mediaServerService.closeRTPServer(device, channelId); param.put("ssrc",sendRtpItem.getSsrc());
} logger.info("停止向上级推流:" + streamId);
} MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
} catch (SipException e) { zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
e.printStackTrace(); redisCatchStorage.deleteSendRTPServer(platformGbId, channelId);
} catch (InvalidArgumentException e) { if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) {
e.printStackTrace(); logger.info(streamId + "无其它观看者,通知设备停止推流");
} catch (ParseException e) { cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId);
e.printStackTrace(); }
} }
} // 可能是设备主动停止
Device device = storager.queryVideoDeviceByChannelId(platformGbId);
/*** if (device != null) {
* 回复200 OK StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
* @param evt if (streamInfo != null) {
* @throws SipException redisCatchStorage.stopPlay(streamInfo);
* @throws InvalidArgumentException }
* @throws ParseException storager.stopPlay(device.getDeviceId(), channelId);
*/ mediaServerService.closeRTPServer(device, channelId);
private void responseAck(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { }
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); }
ServerTransaction serverTransaction = getServerTransaction(evt); } catch (SipException e) {
serverTransaction.sendResponse(response); e.printStackTrace();
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); } catch (InvalidArgumentException e) {
} e.printStackTrace();
} catch (ParseException e) {
public IRedisCatchStorage getRedisCatchStorage() { e.printStackTrace();
return redisCatchStorage; }
} }
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
public ZLMRTPServerFactory getZlmrtpServerFactory() {
return zlmrtpServerFactory;
}
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
this.zlmrtpServerFactory = zlmrtpServerFactory;
}
public ISIPCommander getSIPCommander() {
return cmder;
}
public void setSIPCommander(ISIPCommander cmder) {
this.cmder = cmder;
}
public IMediaServerService getMediaServerService() {
return mediaServerService;
}
public void setMediaServerService(IMediaServerService mediaServerService) {
this.mediaServerService = mediaServerService;
}
public IVideoManagerStorager getStorager() {
return storager;
}
public void setStorager(IVideoManagerStorager storager) {
this.storager = storager;
}
}

View File

@ -0,0 +1,40 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.RequestEvent;
/**
* SIP命令类型 CANCEL请求
*/
@Component
public class CancelRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private String method = "CANCEL";
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
}
/**
* 处理CANCEL请求
*
* @param evt 事件
*/
@Override
public void process(RequestEvent evt) {
// TODO 优先级99 Cancel Request消息实现此消息一般为级联消息上级给下级发送请求取消指令
}
}

View File

@ -1,478 +1,395 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import javax.sdp.*; import com.genersoft.iot.vmp.gb28181.bean.*;
import javax.sip.*; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import javax.sip.address.Address; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import javax.sip.address.SipURI; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import javax.sip.header.*; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import javax.sip.message.Request; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import javax.sip.message.Response; import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import gov.nist.javax.sip.address.AddressImpl;
import com.genersoft.iot.vmp.service.IMediaServerService; import gov.nist.javax.sip.address.SipUri;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import org.slf4j.Logger;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.slf4j.LoggerFactory;
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; import org.springframework.beans.factory.InitializingBean;
import com.genersoft.iot.vmp.service.IPlayService; import org.springframework.beans.factory.annotation.Autowired;
import gov.nist.javax.sip.address.AddressImpl; import org.springframework.stereotype.Component;
import gov.nist.javax.sip.address.SipUri;
import org.slf4j.Logger; import javax.sdp.*;
import org.slf4j.LoggerFactory; import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import java.text.ParseException; import javax.sip.ServerTransaction;
import java.util.Vector; import javax.sip.SipException;
import javax.sip.address.SipURI;
/** import javax.sip.header.FromHeader;
* @Description:处理INVITE请求 import javax.sip.message.Request;
* @author: panll import javax.sip.message.Response;
* @date: 2021年1月14日 import java.text.ParseException;
*/ import java.util.Vector;
@SuppressWarnings("rawtypes")
public class InviteRequestProcessor extends SIPRequestAbstractProcessor { /**
* SIP命令类型 INVITE请求
private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class); */
@SuppressWarnings("rawtypes")
private SIPCommanderFroPlatform cmderFroPlatform; @Component
public class InviteRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private IVideoManagerStorager storager;
private final static Logger logger = LoggerFactory.getLogger(InviteRequestProcessor.class);
private IRedisCatchStorage redisCatchStorage;
private String method = "INVITE";
private SIPCommander cmder;
@Autowired
private IPlayService playService; private SIPCommanderFroPlatform cmderFroPlatform;
private ZLMRTPServerFactory zlmrtpServerFactory; @Autowired
private IVideoManagerStorager storager;
private IMediaServerService mediaServerService;
@Autowired
public ZLMRTPServerFactory getZlmrtpServerFactory() { private IRedisCatchStorage redisCatchStorage;
return zlmrtpServerFactory;
} @Autowired
private SIPCommander cmder;
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
this.zlmrtpServerFactory = zlmrtpServerFactory; @Autowired
} private IPlayService playService;
/** @Autowired
* 处理invite请求 private ZLMRTPServerFactory zlmrtpServerFactory;
*
* @param evt @Autowired
* 请求消息 private IMediaServerService mediaServerService;
*/
@Override @Autowired
public void process(RequestEvent evt) { private SIPProcessorObserver sipProcessorObserver;
// Invite Request消息实现此消息一般为级联消息上级给下级发送请求视频指令
try { @Override
Request request = evt.getRequest(); public void afterPropertiesSet() throws Exception {
SipURI sipURI = (SipURI) request.getRequestURI(); // 添加消息处理的订阅
String channelId = sipURI.getUser(); sipProcessorObserver.addRequestProcessor(method, this);
String requesterId = null; }
FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); /**
AddressImpl address = (AddressImpl) fromHeader.getAddress(); * 处理invite请求
SipUri uri = (SipUri) address.getURI(); *
requesterId = uri.getUser(); * @param evt
* 请求消息
if (requesterId == null || channelId == null) { */
logger.info("无法从FromHeader的Address中获取到平台id返回400"); @Override
responseAck(evt, Response.BAD_REQUEST); // 参数不全 发400请求错误 public void process(RequestEvent evt) {
return; // Invite Request消息实现此消息一般为级联消息上级给下级发送请求视频指令
} try {
Request request = evt.getRequest();
// 查询请求方是否上级平台 SipURI sipURI = (SipURI) request.getRequestURI();
ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId); String channelId = sipURI.getUser();
if (platform != null) { String requesterId = null;
// 查询平台下是否有该通道
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId); AddressImpl address = (AddressImpl) fromHeader.getAddress();
MediaServerItem mediaServerItem = null; SipUri uri = (SipUri) address.getURI();
// 不是通道可能是直播流 requesterId = uri.getUser();
if (channel != null && gbStream == null ) {
if (channel.getStatus() == 0) { if (requesterId == null || channelId == null) {
logger.info("通道离线返回400"); logger.info("无法从FromHeader的Address中获取到平台id返回400");
responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline"); responseAck(evt, Response.BAD_REQUEST); // 参数不全 发400请求错误
return; return;
} }
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在发181呼叫转接中
}else if(channel == null && gbStream != null){ // 查询请求方是否上级平台
String mediaServerId = gbStream.getMediaServerId(); ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
mediaServerItem = mediaServerService.getOne(mediaServerId); if (platform != null) {
if (mediaServerItem == null) { // 查询平台下是否有该通道
logger.info("[ app={}, stream={} ]zlm找不到返回410",gbStream.getApp(), gbStream.getStream()); DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
responseAck(evt, Response.GONE, "media server not found"); GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
return; MediaServerItem mediaServerItem = null;
} // 不是通道可能是直播流
Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); if (channel != null && gbStream == null ) {
if (!streamReady ) { if (channel.getStatus() == 0) {
logger.info("[ app={}, stream={} ]通道离线返回400",gbStream.getApp(), gbStream.getStream()); logger.info("通道离线返回400");
responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline"); responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline");
return; return;
} }
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在发181呼叫转接中 responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在发181呼叫转接中
}else { }else if(channel == null && gbStream != null){
logger.info("通道不存在返回404"); String mediaServerId = gbStream.getMediaServerId();
responseAck(evt, Response.NOT_FOUND); // 通道不存在发404资源不存在 mediaServerItem = mediaServerService.getOne(mediaServerId);
return; if (mediaServerItem == null) {
} logger.info("[ app={}, stream={} ]找不到zlm {}返回410",gbStream.getApp(), gbStream.getStream(), mediaServerId);
// 解析sdp消息, 使用jainsip 自带的sdp解析方式 responseAck(evt, Response.GONE, "media server not found");
String contentString = new String(request.getRawContent()); return;
}
// jainSip不支持y=字段 移除移除以解析 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
int ssrcIndex = contentString.indexOf("y="); if (!streamReady ) {
//ssrc规定长度为10字节不取余下长度以避免后续还有f=字段 logger.info("[ app={}, stream={} ]通道离线返回400",gbStream.getApp(), gbStream.getStream());
String ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
String substring = contentString.substring(0, contentString.indexOf("y=")); return;
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); }
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在发181呼叫转接中
// 获取支持的格式 }else {
Vector mediaDescriptions = sdp.getMediaDescriptions(true); logger.info("通道不存在返回404");
// 查看是否支持PS 负载96 responseAck(evt, Response.NOT_FOUND); // 通道不存在发404资源不存在
//String ip = null; return;
int port = -1; }
//boolean recvonly = false; // 解析sdp消息, 使用jainsip 自带的sdp解析方式
boolean mediaTransmissionTCP = false; String contentString = new String(request.getRawContent());
Boolean tcpActive = null;
for (Object description : mediaDescriptions) { // jainSip不支持y=字段 移除以解析
MediaDescription mediaDescription = (MediaDescription) description; int ssrcIndex = contentString.indexOf("y=");
Media media = mediaDescription.getMedia(); // 检查是否有y字段
String ssrcDefault = "0000000000";
Vector mediaFormats = media.getMediaFormats(false); String ssrc;
if (mediaFormats.contains("96")) { SessionDescription sdp;
port = media.getMediaPort(); if (ssrcIndex >= 0) {
//String mediaType = media.getMediaType(); //ssrc规定长度为10字节不取余下长度以避免后续还有f=字段
String protocol = media.getProtocol(); ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
String substring = contentString.substring(0, contentString.indexOf("y="));
// 区分TCP发流还是udp 当前默认udp sdp = SdpFactory.getInstance().createSessionDescription(substring);
if ("TCP/RTP/AVP".equals(protocol)) { }else {
String setup = mediaDescription.getAttribute("setup"); ssrc = ssrcDefault;
if (setup != null) { sdp = SdpFactory.getInstance().createSessionDescription(contentString);
mediaTransmissionTCP = true; }
if ("active".equals(setup)) {
tcpActive = true; // 获取支持的格式
} else if ("passive".equals(setup)) { Vector mediaDescriptions = sdp.getMediaDescriptions(true);
tcpActive = false; // 查看是否支持PS 负载96
} //String ip = null;
} int port = -1;
} //boolean recvonly = false;
break; boolean mediaTransmissionTCP = false;
} Boolean tcpActive = null;
} for (Object description : mediaDescriptions) {
if (port == -1) { MediaDescription mediaDescription = (MediaDescription) description;
logger.info("不支持的媒体格式返回415"); Media media = mediaDescription.getMedia();
// 回复不支持的格式
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式发415 Vector mediaFormats = media.getMediaFormats(false);
return; if (mediaFormats.contains("96")) {
} port = media.getMediaPort();
String username = sdp.getOrigin().getUsername(); //String mediaType = media.getMediaType();
String addressStr = sdp.getOrigin().getAddress(); String protocol = media.getProtocol();
//String sessionName = sdp.getSessionName().getValue();
logger.info("[上级点播]用户:{} 地址:{}:{} ssrc{}", username, addressStr, port, ssrc); // 区分TCP发流还是udp 当前默认udp
Device device = null; if ("TCP/RTP/AVP".equals(protocol)) {
// 通过 channel gbStream 是否为null 值判断来源是直播流合适国标 String setup = mediaDescription.getAttribute("setup");
if (channel != null) { if (setup != null) {
device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId); mediaTransmissionTCP = true;
if (device == null) { if ("active".equals(setup)) {
logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel); tcpActive = true;
responseAck(evt, Response.SERVER_INTERNAL_ERROR); } else if ("passive".equals(setup)) {
return; tcpActive = false;
} }
mediaServerItem = playService.getNewMediaServerItem(device); }
if (mediaServerItem == null) { }
logger.warn("未找到可用的zlm"); break;
responseAck(evt, Response.BUSY_HERE); }
return; }
} if (port == -1) {
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, logger.info("不支持的媒体格式返回415");
device.getDeviceId(), channelId, // 回复不支持的格式
mediaTransmissionTCP); responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式发415
if (tcpActive != null) { return;
sendRtpItem.setTcpActive(tcpActive); }
} String username = sdp.getOrigin().getUsername();
if (sendRtpItem == null) { String addressStr = sdp.getOrigin().getAddress();
logger.warn("服务器端口资源不足"); //String sessionName = sdp.getSessionName().getValue();
responseAck(evt, Response.BUSY_HERE); logger.info("[上级点播]用户:{} 地址:{}:{} ssrc{}", username, addressStr, port, ssrc);
return; Device device = null;
} // 通过 channel gbStream 是否为null 值判断来源是直播流合适国标
if (channel != null) {
// 写入redis 超时时回复 device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId);
redisCatchStorage.updateSendRTPSever(sendRtpItem); if (device == null) {
// 通知下级推流 logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel);
PlayResult playResult = playService.play(mediaServerItem,device.getDeviceId(), channelId, (mediaServerItemInUSe, responseJSON)->{ responseAck(evt, Response.SERVER_INTERNAL_ERROR);
// 收到推流 回复200OK, 等待ack return;
// if (sendRtpItem == null) return; }
sendRtpItem.setStatus(1); mediaServerItem = playService.getNewMediaServerItem(device);
redisCatchStorage.updateSendRTPSever(sendRtpItem); if (mediaServerItem == null) {
// TODO 添加对tcp的支持 logger.warn("未找到可用的zlm");
responseAck(evt, Response.BUSY_HERE);
StringBuffer content = new StringBuffer(200); return;
content.append("v=0\r\n"); }
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n"); SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
content.append("s=Play\r\n"); device.getDeviceId(), channelId,
content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n"); mediaTransmissionTCP);
content.append("t=0 0\r\n"); if (tcpActive != null) {
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n"); sendRtpItem.setTcpActive(tcpActive);
content.append("a=sendonly\r\n"); }
content.append("a=rtpmap:96 PS/90000\r\n"); if (sendRtpItem == null) {
content.append("y="+ ssrc + "\r\n"); logger.warn("服务器端口资源不足");
content.append("f=\r\n"); responseAck(evt, Response.BUSY_HERE);
return;
try { }
responseAck(evt, content.toString());
} catch (SipException e) { // 写入redis 超时时回复
e.printStackTrace(); redisCatchStorage.updateSendRTPSever(sendRtpItem);
} catch (InvalidArgumentException e) { // 通知下级推流
e.printStackTrace(); PlayResult playResult = playService.play(mediaServerItem,device.getDeviceId(), channelId, (mediaServerItemInUSe, responseJSON)->{
} catch (ParseException e) { // 收到推流 回复200OK, 等待ack
e.printStackTrace(); // if (sendRtpItem == null) return;
} sendRtpItem.setStatus(1);
} ,((event) -> { redisCatchStorage.updateSendRTPSever(sendRtpItem);
// 未知错误直接转发设备点播的错误 // TODO 添加对tcp的支持
Response response = null;
try { StringBuffer content = new StringBuffer(200);
response = getMessageFactory().createResponse(event.getResponse().getStatusCode(), evt.getRequest()); content.append("v=0\r\n");
ServerTransaction serverTransaction = getServerTransaction(evt); content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
serverTransaction.sendResponse(response); content.append("s=Play\r\n");
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
} catch (ParseException | SipException | InvalidArgumentException e) { content.append("t=0 0\r\n");
e.printStackTrace(); content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
} content.append("a=sendonly\r\n");
})); content.append("a=rtpmap:96 PS/90000\r\n");
if (logger.isDebugEnabled()) { content.append("y="+ ssrc + "\r\n");
logger.debug(playResult.getResult().toString()); content.append("f=\r\n");
}
try {
}else if (gbStream != null) { responseAck(evt, content.toString());
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, } catch (SipException e) {
gbStream.getApp(), gbStream.getStream(), channelId, e.printStackTrace();
mediaTransmissionTCP); } catch (InvalidArgumentException e) {
e.printStackTrace();
if (tcpActive != null) { } catch (ParseException e) {
sendRtpItem.setTcpActive(tcpActive); e.printStackTrace();
} }
if (sendRtpItem == null) { } ,((event) -> {
logger.warn("服务器端口资源不足"); // 未知错误直接转发设备点播的错误
responseAck(evt, Response.BUSY_HERE); Response response = null;
return; try {
} response = getMessageFactory().createResponse(event.statusCode, evt.getRequest());
ServerTransaction serverTransaction = getServerTransaction(evt);
// 写入redis 超时时回复 serverTransaction.sendResponse(response);
redisCatchStorage.updateSendRTPSever(sendRtpItem); if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
} catch (ParseException | SipException | InvalidArgumentException e) {
sendRtpItem.setStatus(1); e.printStackTrace();
redisCatchStorage.updateSendRTPSever(sendRtpItem); }
// TODO 添加对tcp的支持 }));
StringBuffer content = new StringBuffer(200); if (logger.isDebugEnabled()) {
content.append("v=0\r\n"); logger.debug(playResult.getResult().toString());
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); }
content.append("s=Play\r\n");
content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); }else if (gbStream != null) {
content.append("t=0 0\r\n"); SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n"); gbStream.getApp(), gbStream.getStream(), channelId,
content.append("a=sendonly\r\n"); mediaTransmissionTCP);
content.append("a=rtpmap:96 PS/90000\r\n");
content.append("y="+ ssrc + "\r\n"); if (tcpActive != null) {
content.append("f=\r\n"); sendRtpItem.setTcpActive(tcpActive);
}
try { if (sendRtpItem == null) {
responseAck(evt, content.toString()); logger.warn("服务器端口资源不足");
} catch (SipException e) { responseAck(evt, Response.BUSY_HERE);
e.printStackTrace(); return;
} catch (InvalidArgumentException e) { }
e.printStackTrace();
} catch (ParseException e) { // 写入redis 超时时回复
e.printStackTrace(); redisCatchStorage.updateSendRTPSever(sendRtpItem);
}
} sendRtpItem.setStatus(1);
redisCatchStorage.updateSendRTPSever(sendRtpItem);
} else { // TODO 添加对tcp的支持
// 非上级平台请求查询是否设备请求通常为接收语音广播的设备 StringBuffer content = new StringBuffer(200);
Device device = storager.queryVideoDevice(requesterId); content.append("v=0\r\n");
if (device != null) { content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
logger.info("收到设备" + requesterId + "的语音广播Invite请求"); content.append("s=Play\r\n");
responseAck(evt, Response.TRYING); content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
content.append("t=0 0\r\n");
String contentString = new String(request.getRawContent()); content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
// jainSip不支持y=字段 移除移除以解析 content.append("a=sendonly\r\n");
String substring = contentString; content.append("a=rtpmap:96 PS/90000\r\n");
String ssrc = "0000000404"; content.append("y="+ ssrc + "\r\n");
int ssrcIndex = contentString.indexOf("y="); content.append("f=\r\n");
if (ssrcIndex > 0) {
substring = contentString.substring(0, ssrcIndex); try {
ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); responseAck(evt, content.toString());
} } catch (SipException e) {
ssrcIndex = substring.indexOf("f="); e.printStackTrace();
if (ssrcIndex > 0) { } catch (InvalidArgumentException e) {
substring = contentString.substring(0, ssrcIndex); e.printStackTrace();
} } catch (ParseException e) {
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); e.printStackTrace();
}
// 获取支持的格式 }
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
// 查看是否支持PS 负载96 } else {
int port = -1; // 非上级平台请求查询是否设备请求通常为接收语音广播的设备
//boolean recvonly = false; Device device = storager.queryVideoDevice(requesterId);
boolean mediaTransmissionTCP = false; if (device != null) {
Boolean tcpActive = null; logger.info("收到设备" + requesterId + "的语音广播Invite请求");
for (int i = 0; i < mediaDescriptions.size(); i++) { responseAck(evt, Response.TRYING);
MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
Media media = mediaDescription.getMedia(); String contentString = new String(request.getRawContent());
// jainSip不支持y=字段 移除移除以解析
Vector mediaFormats = media.getMediaFormats(false); String substring = contentString;
if (mediaFormats.contains("8")) { String ssrc = "0000000404";
port = media.getMediaPort(); int ssrcIndex = contentString.indexOf("y=");
String protocol = media.getProtocol(); if (ssrcIndex > 0) {
// 区分TCP发流还是udp 当前默认udp substring = contentString.substring(0, ssrcIndex);
if ("TCP/RTP/AVP".equals(protocol)) { ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
String setup = mediaDescription.getAttribute("setup"); }
if (setup != null) { ssrcIndex = substring.indexOf("f=");
mediaTransmissionTCP = true; if (ssrcIndex > 0) {
if ("active".equals(setup)) { substring = contentString.substring(0, ssrcIndex);
tcpActive = true; }
} else if ("passive".equals(setup)) { SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
tcpActive = false;
} // 获取支持的格式
} Vector mediaDescriptions = sdp.getMediaDescriptions(true);
} // 查看是否支持PS 负载96
break; int port = -1;
} //boolean recvonly = false;
} boolean mediaTransmissionTCP = false;
if (port == -1) { Boolean tcpActive = null;
logger.info("不支持的媒体格式返回415"); for (int i = 0; i < mediaDescriptions.size(); i++) {
// 回复不支持的格式 MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式发415 Media media = mediaDescription.getMedia();
return;
} Vector mediaFormats = media.getMediaFormats(false);
String username = sdp.getOrigin().getUsername(); if (mediaFormats.contains("8")) {
String addressStr = sdp.getOrigin().getAddress(); port = media.getMediaPort();
logger.info("设备{}请求语音流,地址:{}:{}ssrc{}", username, addressStr, port, ssrc); String protocol = media.getProtocol();
// 区分TCP发流还是udp 当前默认udp
} else { if ("TCP/RTP/AVP".equals(protocol)) {
logger.warn("来自无效设备/平台的请求"); String setup = mediaDescription.getAttribute("setup");
responseAck(evt, Response.BAD_REQUEST); if (setup != null) {
} mediaTransmissionTCP = true;
} if ("active".equals(setup)) {
tcpActive = true;
} catch (SipException | InvalidArgumentException | ParseException e) { } else if ("passive".equals(setup)) {
e.printStackTrace(); tcpActive = false;
logger.warn("sdp解析错误"); }
e.printStackTrace(); }
} catch (SdpParseException e) { }
e.printStackTrace(); break;
} catch (SdpException e) { }
e.printStackTrace(); }
} if (port == -1) {
} logger.info("不支持的媒体格式返回415");
// 回复不支持的格式
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式发415
/*** return;
* 回复状态码 }
* 100 trying String username = sdp.getOrigin().getUsername();
* 200 OK String addressStr = sdp.getOrigin().getAddress();
* 400 logger.info("设备{}请求语音流,地址:{}:{}ssrc{}", username, addressStr, port, ssrc);
* 404
* @param evt } else {
* @throws SipException logger.warn("来自无效设备/平台的请求");
* @throws InvalidArgumentException responseAck(evt, Response.BAD_REQUEST);
* @throws ParseException }
*/ }
private void responseAck(RequestEvent evt, int statusCode) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest()); } catch (SipException | InvalidArgumentException | ParseException e) {
ServerTransaction serverTransaction = getServerTransaction(evt); e.printStackTrace();
serverTransaction.sendResponse(response); logger.warn("sdp解析错误");
if (statusCode >= 200) { e.printStackTrace();
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); } catch (SdpParseException e) {
} e.printStackTrace();
} } catch (SdpException e) {
e.printStackTrace();
private void responseAck(RequestEvent evt, int statusCode, String msg) throws SipException, InvalidArgumentException, ParseException { }
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest()); }
response.setReasonPhrase(msg); }
ServerTransaction serverTransaction = getServerTransaction(evt);
serverTransaction.sendResponse(response);
if (statusCode >= 200) {
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
}
}
/**
* 回复带sdp的200
* @param evt
* @param sdp
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
SipFactory sipFactory = SipFactory.getInstance();
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
response.setContent(sdp, contentTypeHeader);
SipURI sipURI = (SipURI)evt.getRequest().getRequestURI();
Address concatAddress = sipFactory.createAddressFactory().createAddress(
sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost()+":"+sipURI.getPort()
));
response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
getServerTransaction(evt).sendResponse(response);
}
public SIPCommanderFroPlatform getCmderFroPlatform() {
return cmderFroPlatform;
}
public void setCmderFroPlatform(SIPCommanderFroPlatform cmderFroPlatform) {
this.cmderFroPlatform = cmderFroPlatform;
}
public IVideoManagerStorager getStorager() {
return storager;
}
public void setStorager(IVideoManagerStorager storager) {
this.storager = storager;
}
public SIPCommander getCmder() {
return cmder;
}
public void setCmder(SIPCommander cmder) {
this.cmder = cmder;
}
public IPlayService getPlayService() {
return playService;
}
public void setPlayService(IPlayService playService) {
this.playService = playService;
}
public IRedisCatchStorage getRedisCatchStorage() {
return redisCatchStorage;
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
public IMediaServerService getMediaServerService() {
return mediaServerService;
}
public void setMediaServerService(IMediaServerService mediaServerService) {
this.mediaServerService = mediaServerService;
}
}

View File

@ -1,67 +1,76 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import java.io.ByteArrayInputStream;
import java.text.ParseException;
import java.util.Iterator;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.message.Request;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.GpsUtil; import com.genersoft.iot.vmp.utils.GpsUtil;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Iterator;
/** /**
* @Description: Notify请求处理器 * SIP命令类型 NOTIFY请求
* @author: lawrencehj
* @date: 2021年1月27日
*/ */
@Component
public class NotifyRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
private UserSetup userSetup = (UserSetup) SpringBeanFactory.getBean("userSetup");
private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class); private final static Logger logger = LoggerFactory.getLogger(NotifyRequestProcessor.class);
@Autowired
private UserSetup userSetup;
@Autowired
private IVideoManagerStorager storager; private IVideoManagerStorager storager;
@Autowired
private IRedisCatchStorage redisCatchStorage; private IRedisCatchStorage redisCatchStorage;
@Autowired
private EventPublisher publisher; private EventPublisher publisher;
@Autowired
private DeviceOffLineDetector offLineDetector; private DeviceOffLineDetector offLineDetector;
private static final String NOTIFY_CATALOG = "Catalog"; private static final String NOTIFY_CATALOG = "Catalog";
private static final String NOTIFY_ALARM = "Alarm"; private static final String NOTIFY_ALARM = "Alarm";
private static final String NOTIFY_MOBILE_POSITION = "MobilePosition"; private static final String NOTIFY_MOBILE_POSITION = "MobilePosition";
private String method = "NOTIFY";
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
}
@Override @Override
public void process(RequestEvent evt) { public void process(RequestEvent evt) {
@ -80,7 +89,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
processNotifyMobilePosition(evt); processNotifyMobilePosition(evt);
} else { } else {
logger.info("接收到消息:" + cmd); logger.info("接收到消息:" + cmd);
response200Ok(evt); responseAck(evt, Response.OK);
} }
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace(); e.printStackTrace();
@ -135,7 +144,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
storager.clearMobilePositionsByDeviceId(deviceId); storager.clearMobilePositionsByDeviceId(deviceId);
} }
storager.insertMobilePosition(mobilePosition); storager.insertMobilePosition(mobilePosition);
response200Ok(evt); responseAck(evt, Response.OK);
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -199,7 +208,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
// TODO: 需要实现存储报警信息报警分类 // TODO: 需要实现存储报警信息报警分类
// 回复200 OK // 回复200 OK
response200Ok(evt); responseAck(evt, Response.OK);
if (offLineDetector.isOnline(deviceId)) { if (offLineDetector.isOnline(deviceId)) {
publisher.deviceAlarmEventPublish(deviceAlarm); publisher.deviceAlarmEventPublish(deviceAlarm);
} }
@ -215,10 +224,14 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
*/ */
private void processNotifyCatalogList(RequestEvent evt) { private void processNotifyCatalogList(RequestEvent evt) {
try { try {
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader);
Element rootElement = getRootElement(evt); Element rootElement = getRootElement(evt);
Element deviceIdElement = rootElement.element("DeviceID");
String deviceId = deviceIdElement.getText();
Device device = storager.queryVideoDevice(deviceId); Device device = storager.queryVideoDevice(deviceId);
if (device == null) {
return;
}
if (device != null ) { if (device != null ) {
rootElement = getRootElement(evt, device.getCharset()); rootElement = getRootElement(evt, device.getCharset());
} }
@ -228,9 +241,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
} }
Iterator<Element> deviceListIterator = deviceListElement.elementIterator(); Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
if (deviceListIterator != null) { if (deviceListIterator != null) {
if (device == null) {
return;
}
// 遍历DeviceList // 遍历DeviceList
while (deviceListIterator.hasNext()) { while (deviceListIterator.hasNext()) {
Element itemDevice = deviceListIterator.next(); Element itemDevice = deviceListIterator.next();
@ -238,87 +249,51 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
if (channelDeviceElement == null) { if (channelDeviceElement == null) {
continue; continue;
} }
String channelDeviceId = channelDeviceElement.getTextTrim(); Element eventElement = itemDevice.element("Event");
Element channdelNameElement = itemDevice.element("Name"); DeviceChannel channel = channelContentHander(itemDevice);
String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : ""; switch (eventElement.getText().toUpperCase()) {
Element statusElement = itemDevice.element("Status"); case "ON" : // 上线
String status = statusElement != null ? statusElement.getTextTrim().toString() : "ON"; logger.info("收到来自设备【{}】的通道【{}】上线通知", device.getDeviceId(), channel.getChannelId());
DeviceChannel deviceChannel = new DeviceChannel(); storager.deviceChannelOnline(deviceId, channel.getChannelId());
deviceChannel.setName(channelName); // 回复200 OK
deviceChannel.setChannelId(channelDeviceId); responseAck(evt, Response.OK);
// ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 break;
if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) { case "OFF" : // 离线
deviceChannel.setStatus(1); logger.info("收到来自设备【{}】的通道【{}】离线通知", device.getDeviceId(), channel.getChannelId());
} storager.deviceChannelOffline(deviceId, channel.getChannelId());
if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { // 回复200 OK
deviceChannel.setStatus(0); responseAck(evt, Response.OK);
break;
case "VLOST" : // 视频丢失
logger.info("收到来自设备【{}】的通道【{}】视频丢失通知", device.getDeviceId(), channel.getChannelId());
storager.deviceChannelOffline(deviceId, channel.getChannelId());
// 回复200 OK
responseAck(evt, Response.OK);
break;
case "DEFECT" : // 故障
// 回复200 OK
responseAck(evt, Response.OK);
break;
case "ADD" : // 增加
logger.info("收到来自设备【{}】的增加通道【{}】通知", device.getDeviceId(), channel.getChannelId());
storager.updateChannel(deviceId, channel);
responseAck(evt, Response.OK);
break;
case "DEL" : // 删除
logger.info("收到来自设备【{}】的删除通道【{}】通知", device.getDeviceId(), channel.getChannelId());
storager.delChannel(deviceId, channel.getChannelId());
responseAck(evt, Response.OK);
break;
case "UPDATE" : // 更新
logger.info("收到来自设备【{}】的更新通道【{}】通知", device.getDeviceId(), channel.getChannelId());
storager.updateChannel(deviceId, channel);
responseAck(evt, Response.OK);
break;
default:
responseAck(evt, Response.BAD_REQUEST, "event not found");
} }
deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode"));
deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
if (XmlUtil.getText(itemDevice, "Parental") == null
|| XmlUtil.getText(itemDevice, "Parental") == "") {
deviceChannel.setParental(0);
} else {
deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental")));
}
deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID"));
if (XmlUtil.getText(itemDevice, "SafetyWay") == null
|| XmlUtil.getText(itemDevice, "SafetyWay") == "") {
deviceChannel.setSafetyWay(0);
} else {
deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay")));
}
if (XmlUtil.getText(itemDevice, "RegisterWay") == null
|| XmlUtil.getText(itemDevice, "RegisterWay") == "") {
deviceChannel.setRegisterWay(1);
} else {
deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay")));
}
deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum"));
if (XmlUtil.getText(itemDevice, "Certifiable") == null
|| XmlUtil.getText(itemDevice, "Certifiable") == "") {
deviceChannel.setCertifiable(0);
} else {
deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable")));
}
if (XmlUtil.getText(itemDevice, "ErrCode") == null
|| XmlUtil.getText(itemDevice, "ErrCode") == "") {
deviceChannel.setErrCode(0);
} else {
deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode")));
}
deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime"));
deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy"));
deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress"));
if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") {
deviceChannel.setPort(0);
} else {
deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port")));
}
deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {
deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude")));
} else {
deviceChannel.setLongitude(0.00);
}
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) {
deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude")));
} else {
deviceChannel.setLatitude(0.00);
}
if (XmlUtil.getText(itemDevice, "PTZType") == null
|| XmlUtil.getText(itemDevice, "PTZType") == "") {
deviceChannel.setPTZType(0);
} else {
deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
}
deviceChannel.setHasAudio(true); // 默认含有音频播放时再检查是否有音频及是否AAC
storager.updateChannel(device.getDeviceId(), deviceChannel);
} }
// RequestMessage msg = new RequestMessage(); // RequestMessage msg = new RequestMessage();
@ -326,8 +301,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
// msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG); // msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG);
// msg.setData(device); // msg.setData(device);
// deferredResultHolder.invokeResult(msg); // deferredResultHolder.invokeResult(msg);
// 回复200 OK
response200Ok(evt);
if (offLineDetector.isOnline(deviceId)) { if (offLineDetector.isOnline(deviceId)) {
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
} }
@ -337,32 +311,93 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
} }
} }
/*** public DeviceChannel channelContentHander(Element itemDevice){
* 回复200 OK Element channdelNameElement = itemDevice.element("Name");
* String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : "";
* @param evt Element statusElement = itemDevice.element("Status");
* @throws SipException String status = statusElement != null ? statusElement.getTextTrim().toString() : "ON";
* @throws InvalidArgumentException DeviceChannel deviceChannel = new DeviceChannel();
* @throws ParseException deviceChannel.setName(channelName);
*/ Element channdelIdElement = itemDevice.element("DeviceID");
private void response200Ok(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { String channelId = channdelIdElement != null ? channdelIdElement.getTextTrim().toString() : "";
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); deviceChannel.setChannelId(channelId);
ServerTransaction serverTransaction = getServerTransaction(evt); // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
serverTransaction.sendResponse(response); if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) {
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); deviceChannel.setStatus(1);
} }
private Element getRootElement(RequestEvent evt) throws DocumentException { if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
return getRootElement(evt, "gb2312"); deviceChannel.setStatus(0);
} }
private Element getRootElement(RequestEvent evt, String charset) throws DocumentException {
if (charset == null) charset = "gb2312"; deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
Request request = evt.getRequest(); deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
SAXReader reader = new SAXReader(); deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
reader.setEncoding(charset); deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode"));
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent())); deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
return xml.getRootElement(); deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
if (XmlUtil.getText(itemDevice, "Parental") == null
|| XmlUtil.getText(itemDevice, "Parental") == "") {
deviceChannel.setParental(0);
} else {
deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental")));
}
deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID"));
if (XmlUtil.getText(itemDevice, "SafetyWay") == null
|| XmlUtil.getText(itemDevice, "SafetyWay") == "") {
deviceChannel.setSafetyWay(0);
} else {
deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay")));
}
if (XmlUtil.getText(itemDevice, "RegisterWay") == null
|| XmlUtil.getText(itemDevice, "RegisterWay") == "") {
deviceChannel.setRegisterWay(1);
} else {
deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay")));
}
deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum"));
if (XmlUtil.getText(itemDevice, "Certifiable") == null
|| XmlUtil.getText(itemDevice, "Certifiable") == "") {
deviceChannel.setCertifiable(0);
} else {
deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable")));
}
if (XmlUtil.getText(itemDevice, "ErrCode") == null
|| XmlUtil.getText(itemDevice, "ErrCode") == "") {
deviceChannel.setErrCode(0);
} else {
deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode")));
}
deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime"));
deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy"));
deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress"));
if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") {
deviceChannel.setPort(0);
} else {
deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port")));
}
deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {
deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude")));
} else {
deviceChannel.setLongitude(0.00);
}
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) {
deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude")));
} else {
deviceChannel.setLatitude(0.00);
}
if (XmlUtil.getText(itemDevice, "PTZType") == null
|| XmlUtil.getText(itemDevice, "PTZType") == "") {
deviceChannel.setPTZType(0);
} else {
deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
}
deviceChannel.setHasAudio(true); // 默认含有音频播放时再检查是否有音频及是否AAC
return deviceChannel;
} }
public void setCmder(SIPCommander cmder) { public void setCmder(SIPCommander cmder) {
} }

View File

@ -1,201 +1,197 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import java.security.NoSuchAlgorithmException; import com.genersoft.iot.vmp.common.VideoManagerConstants;
import java.text.ParseException; import com.genersoft.iot.vmp.conf.SipConfig;
import java.util.Calendar; import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper;
import java.util.Locale; import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import javax.sip.InvalidArgumentException; import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate;
import javax.sip.RequestEvent; import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import javax.sip.ServerTransaction; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import javax.sip.SipException; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import javax.sip.header.AuthorizationHeader; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import javax.sip.header.ContactHeader; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import javax.sip.header.ExpiresHeader; import gov.nist.javax.sip.RequestEventExt;
import javax.sip.header.FromHeader; import gov.nist.javax.sip.address.AddressImpl;
import javax.sip.header.ViaHeader; import gov.nist.javax.sip.address.SipUri;
import javax.sip.message.Request; import gov.nist.javax.sip.header.Expires;
import javax.sip.message.Response; import gov.nist.javax.sip.header.SIPDateHeader;
import org.slf4j.Logger;
import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate; import org.slf4j.LoggerFactory;
import gov.nist.javax.sip.RequestEventExt; import org.springframework.beans.factory.InitializingBean;
import gov.nist.javax.sip.header.SIPDateHeader; import org.springframework.beans.factory.annotation.Autowired;
import org.slf4j.Logger; import org.springframework.stereotype.Component;
import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import com.genersoft.iot.vmp.common.VideoManagerConstants; import javax.sip.RequestEvent;
import com.genersoft.iot.vmp.conf.SipConfig; import javax.sip.ServerTransaction;
import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper; import javax.sip.SipException;
import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler; import javax.sip.header.*;
import com.genersoft.iot.vmp.gb28181.bean.Device; import javax.sip.message.Request;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import javax.sip.message.Response;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import java.security.NoSuchAlgorithmException;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import java.text.ParseException;
import java.util.Calendar;
import gov.nist.javax.sip.address.AddressImpl; import java.util.Locale;
import gov.nist.javax.sip.address.SipUri;
import gov.nist.javax.sip.header.Expires; /**
* SIP命令类型 REGISTER请求
/** */
* @Description:收到注册请求 处理 @Component
* @author: swwheihei public class RegisterRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
* @date: 2020年5月3日 下午4:47:25
*/ private Logger logger = LoggerFactory.getLogger(RegisterRequestProcessor.class);
public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
public String method = "REGISTER";
private Logger logger = LoggerFactory.getLogger(RegisterRequestProcessor.class);
@Autowired
private SipConfig sipConfig; private SipConfig sipConfig;
private RegisterLogicHandler handler; @Autowired
private RegisterLogicHandler handler;
private IVideoManagerStorager storager;
@Autowired
private EventPublisher publisher; private IVideoManagerStorager storager;
/** @Autowired
* 收到注册请求 处理 private EventPublisher publisher;
* @param evt
*/ @Autowired
@Override private SIPProcessorObserver sipProcessorObserver;
public void process(RequestEvent evt) {
try { @Override
RequestEventExt evtExt = (RequestEventExt)evt; public void afterPropertiesSet() throws Exception {
String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort(); // 添加消息处理的订阅
logger.info("[{}] 收到注册请求,开始处理", requestAddress); sipProcessorObserver.addRequestProcessor(method, this);
Request request = evt.getRequest(); }
Response response = null; /**
boolean passwordCorrect = false; * 收到注册请求 处理
// 注册标志 0未携带授权头或者密码错误 1注册成功 2注销成功 * @param evt
int registerFlag = 0; */
FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME); @Override
AddressImpl address = (AddressImpl) fromHeader.getAddress(); public void process(RequestEvent evt) {
SipUri uri = (SipUri) address.getURI(); try {
String deviceId = uri.getUser(); RequestEventExt evtExt = (RequestEventExt)evt;
Device device = storager.queryVideoDevice(deviceId); String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort();
AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); logger.info("[{}] 收到注册请求,开始处理", requestAddress);
// 校验密码是否正确 Request request = evt.getRequest();
if (authorhead != null) {
passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request, Response response = null;
sipConfig.getPassword()); boolean passwordCorrect = false;
} // 注册标志 0未携带授权头或者密码错误 1注册成功 2注销成功
if (StringUtils.isEmpty(sipConfig.getPassword())){ int registerFlag = 0;
passwordCorrect = true; FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
} AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI();
// 未携带授权头或者密码错误 回复401 String deviceId = uri.getUser();
if (authorhead == null ) { Device device = storager.queryVideoDevice(deviceId);
AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
logger.info("[{}] 未携带授权头 回复401", requestAddress); // 校验密码是否正确
response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request); if (authorhead != null) {
new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain()); passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request,
}else { sipConfig.getPassword());
if (!passwordCorrect){ }
// 注册失败 if (StringUtils.isEmpty(sipConfig.getPassword())){
response = getMessageFactory().createResponse(Response.FORBIDDEN, request); passwordCorrect = true;
response.setReasonPhrase("wrong password"); }
logger.info("[{}] 密码错误 回复403", requestAddress);
}else { // 未携带授权头或者密码错误 回复401
// 携带授权头并且密码正确 if (authorhead == null ) {
response = getMessageFactory().createResponse(Response.OK, request);
// 添加date头 logger.info("[{}] 未携带授权头 回复401", requestAddress);
SIPDateHeader dateHeader = new SIPDateHeader(); response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
// 使用自己修改的 new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain());
WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis()); }else {
dateHeader.setDate(wvpSipDate); if (!passwordCorrect){
response.addHeader(dateHeader); // 注册失败
response = getMessageFactory().createResponse(Response.FORBIDDEN, request);
ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME); response.setReasonPhrase("wrong password");
if (expiresHeader == null) { logger.info("[{}] 密码/SIP服务器ID错误, 回复403", requestAddress);
response = getMessageFactory().createResponse(Response.BAD_REQUEST, request); }else {
ServerTransaction serverTransaction = getServerTransaction(evt); // 携带授权头并且密码正确
serverTransaction.sendResponse(response); response = getMessageFactory().createResponse(Response.OK, request);
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); // 添加date头
return; SIPDateHeader dateHeader = new SIPDateHeader();
} // 使用自己修改的
// 添加Contact头 WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis());
response.addHeader(request.getHeader(ContactHeader.NAME)); dateHeader.setDate(wvpSipDate);
// 添加Expires头 response.addHeader(dateHeader);
response.addHeader(request.getExpires());
ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME);
// 获取到通信地址等信息 if (expiresHeader == null) {
ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); response = getMessageFactory().createResponse(Response.BAD_REQUEST, request);
String received = viaHeader.getReceived(); ServerTransaction serverTransaction = getServerTransaction(evt);
int rPort = viaHeader.getRPort(); serverTransaction.sendResponse(response);
// 解析本地地址替代 if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
if (StringUtils.isEmpty(received) || rPort == -1) { return;
received = viaHeader.getHost(); }
rPort = viaHeader.getPort(); // 添加Contact头
} response.addHeader(request.getHeader(ContactHeader.NAME));
// // 添加Expires头
response.addHeader(request.getExpires());
if (device == null) {
device = new Device(); // 获取到通信地址等信息
device.setStreamMode("UDP"); ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
device.setCharset("gb2312"); String received = viaHeader.getReceived();
device.setDeviceId(deviceId); int rPort = viaHeader.getRPort();
device.setFirsRegister(true); // 解析本地地址替代
} if (StringUtils.isEmpty(received) || rPort == -1) {
device.setIp(received); received = viaHeader.getHost();
device.setPort(rPort); rPort = viaHeader.getPort();
device.setHostAddress(received.concat(":").concat(String.valueOf(rPort))); }
// 注销成功 //
if (expiresHeader.getExpires() == 0) {
registerFlag = 2; if (device == null) {
} device = new Device();
// 注册成功 device.setStreamMode("UDP");
else { device.setCharset("gb2312");
device.setExpires(expiresHeader.getExpires()); device.setDeviceId(deviceId);
registerFlag = 1; device.setFirsRegister(true);
// 判断TCP还是UDP }
boolean isTcp = false; device.setIp(received);
ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); device.setPort(rPort);
String transport = reqViaHeader.getTransport(); device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));
if (transport.equals("TCP")) { // 注销成功
isTcp = true; if (expiresHeader.getExpires() == 0) {
} registerFlag = 2;
device.setTransport(isTcp ? "TCP" : "UDP"); }
} // 注册成功
} else {
} device.setExpires(expiresHeader.getExpires());
registerFlag = 1;
ServerTransaction serverTransaction = getServerTransaction(evt); // 判断TCP还是UDP
serverTransaction.sendResponse(response); boolean isTcp = false;
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete(); ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
// 注册成功 String transport = reqViaHeader.getTransport();
// 保存到redis if (transport.equals("TCP")) {
// 下发catelog查询目录 isTcp = true;
if (registerFlag == 1 ) { }
logger.info("[{}] 注册成功! deviceId:" + device.getDeviceId(), requestAddress); device.setTransport(isTcp ? "TCP" : "UDP");
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_REGISTER); }
// 重新注册更新设备和通道以免设备替换或更新后信息无法更新 }
handler.onRegister(device); }
} else if (registerFlag == 2) {
logger.info("[{}] 注销成功! deviceId:" + device.getDeviceId(), requestAddress); ServerTransaction serverTransaction = getServerTransaction(evt);
publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER); serverTransaction.sendResponse(response);
} if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
} catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) { // 注册成功
e.printStackTrace(); // 保存到redis
} // 下发catelog查询目录
if (registerFlag == 1 ) {
} logger.info("[{}] 注册成功! deviceId:" + device.getDeviceId(), requestAddress);
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_REGISTER);
public void setSipConfig(SipConfig sipConfig) { // 重新注册更新设备和通道以免设备替换或更新后信息无法更新
this.sipConfig = sipConfig; handler.onRegister(device);
} } else if (registerFlag == 2) {
logger.info("[{}] 注销成功! deviceId:" + device.getDeviceId(), requestAddress);
public void setHandler(RegisterLogicHandler handler) { publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER);
this.handler = handler; }
} } catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) {
e.printStackTrace();
public void setVideoManagerStorager(IVideoManagerStorager storager) { }
this.storager = storager;
} }
public void setPublisher(EventPublisher publisher) { }
this.publisher = publisher;
}
}

View File

@ -1,62 +1,75 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import java.text.ParseException; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import javax.sip.InvalidArgumentException; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import javax.sip.RequestEvent; import org.slf4j.Logger;
import javax.sip.ServerTransaction; import org.slf4j.LoggerFactory;
import javax.sip.SipException; import org.springframework.beans.factory.InitializingBean;
import javax.sip.header.ExpiresHeader; import org.springframework.beans.factory.annotation.Autowired;
import javax.sip.message.Request; import org.springframework.stereotype.Component;
import javax.sip.message.Response;
import javax.sip.InvalidArgumentException;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import javax.sip.RequestEvent;
import org.slf4j.Logger; import javax.sip.ServerTransaction;
import org.slf4j.LoggerFactory; import javax.sip.SipException;
import javax.sip.header.ExpiresHeader;
/** import javax.sip.message.Request;
* @Description:SUBSCRIBE请求处理器 import javax.sip.message.Response;
* @author: swwheihei import java.text.ParseException;
* @date: 2020年5月3日 下午5:31:20
*/ /**
public class SubscribeRequestProcessor extends SIPRequestAbstractProcessor { * SIP命令类型 SUBSCRIBE请求
*/
private Logger logger = LoggerFactory.getLogger(SubscribeRequestProcessor.class); @Component
public class SubscribeRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
/**
* 处理SUBSCRIBE请求 private Logger logger = LoggerFactory.getLogger(SubscribeRequestProcessor.class);
* private String method = "SUBSCRIBE";
* @param evt
*/ @Autowired
@Override private SIPProcessorObserver sipProcessorObserver;
public void process(RequestEvent evt) {
Request request = evt.getRequest(); @Override
public void afterPropertiesSet() throws Exception {
try { // 添加消息处理的订阅
Response response = null; sipProcessorObserver.addRequestProcessor(method, this);
response = getMessageFactory().createResponse(200, request); }
if (response != null) {
ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30); /**
response.setExpires(expireHeader); * 处理SUBSCRIBE请求
} *
logger.info("response : " + response.toString()); * @param evt
ServerTransaction transaction = getServerTransaction(evt); */
if (transaction != null) { @Override
transaction.sendResponse(response); public void process(RequestEvent evt) {
transaction.getDialog().delete(); Request request = evt.getRequest();
transaction.terminate();
} else { try {
logger.info("processRequest serverTransactionId is null."); Response response = null;
} response = getMessageFactory().createResponse(200, request);
if (response != null) {
} catch (ParseException e) { ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30);
e.printStackTrace(); response.setExpires(expireHeader);
} catch (SipException e) { }
e.printStackTrace(); logger.info("response : " + response.toString());
} catch (InvalidArgumentException e) { ServerTransaction transaction = getServerTransaction(evt);
e.printStackTrace(); if (transaction != null) {
} transaction.sendResponse(response);
transaction.getDialog().delete();
} transaction.terminate();
} else {
} logger.info("processRequest serverTransactionId is null.");
}
} catch (ParseException e) {
e.printStackTrace();
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,23 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import org.dom4j.Element;
import javax.sip.RequestEvent;
public interface IMessageHandler {
/**
* 处理来自设备的信息
* @param evt
* @param device
*/
void handForDevice(RequestEvent evt, Device device, Element element);
/**
* 处理来自平台的信息
* @param evt
* @param parentPlatform
*/
void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element);
}

View File

@ -0,0 +1,40 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import javax.sip.RequestEvent;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent implements IMessageHandler{
public Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
public void addHandler(String cmdType, IMessageHandler messageHandler) {
messageHandlerMap.put(cmdType, messageHandler);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
String cmd = getText(element, "CmdType");
IMessageHandler messageHandler = messageHandlerMap.get(cmd);
if (messageHandler != null) {
messageHandler.handForDevice(evt, device, element);
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
String cmd = getText(element, "CmdType");
IMessageHandler messageHandler = messageHandlerMap.get(cmd);
if (messageHandler != null) {
messageHandler.handForPlatform(evt, parentPlatform, element);
}
}
}

View File

@ -0,0 +1,91 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class MessageRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class);
private final String method = "MESSAGE";
private static Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Autowired
private IVideoManagerStorager storage;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
}
public void addHandler(String name, IMessageHandler handler) {
messageHandlerMap.put(name, handler);
}
@Override
public void process(RequestEvent evt) {
logger.debug("接收到消息:" + evt.getRequest());
String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
// 查询设备是否存在
Device device = storage.queryVideoDevice(deviceId);
// 查询上级平台是否存在
ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId);
try {
if (device == null && parentPlatform == null) {
// 不存在则回复404
responseAck(evt, Response.NOT_FOUND, "device id not found");
}else {
Element rootElement = getRootElement(evt);
String name = rootElement.getName();
IMessageHandler messageHandler = messageHandlerMap.get(name);
if (messageHandler != null) {
if (device != null) {
messageHandler.handForDevice(evt, device, rootElement);
}else { // 由于上面已经判断都为null则直接返回所以这里device和parentPlatform必有一个不为null
messageHandler.handForPlatform(evt, parentPlatform, rootElement);
}
}else {
// 不支持的message
// 不存在则回复415
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE, "Unsupported message type, must Control/Notify/Query/Response");
}
}
} catch (SipException e) {
logger.warn("SIP 回复错误", e);
} catch (InvalidArgumentException e) {
logger.warn("参数无效", e);
} catch (ParseException e) {
logger.warn("SIP回复时解析异常", e);
} catch (DocumentException e) {
logger.warn("解析XML消息内容异常", e);
}
}
}

View File

@ -0,0 +1,27 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.control;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 命令类型 控制命令
* 命令类型 设备控制 远程启动, 录像控制TODO, 报警布防/撤防命令TODO, 报警复位命令TODO,
* 强制关键帧命令TODO, 拉框放大/缩小控制命令TODO, 看守位控制TODO, 报警复位TODO
* 命令类型 设备配置 SVAC编码配置TODO, 音频参数TODO, SVAC解码配置TODO
*/
@Component
public class ControlMessageHandler extends MessageHandlerAbstract implements InitializingBean {
private final String messageType = "Control";
@Autowired
private MessageRequestProcessor messageRequestProcessor;
@Override
public void afterPropertiesSet() throws Exception {
messageRequestProcessor.addHandler(messageType, this);
}
}

View File

@ -0,0 +1,112 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.control.cmd;
import com.genersoft.iot.vmp.VManageBootstrap;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.control.ControlMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
import gov.nist.javax.sip.SipStackImpl;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.ListeningPoint;
import javax.sip.ObjectInUseException;
import javax.sip.RequestEvent;
import javax.sip.SipProvider;
import javax.sip.address.SipURI;
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import java.util.Iterator;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceControlQueryMessageHandler.class);
private final String cmdType = "DeviceControl";
@Autowired
private ControlMessageHandler controlMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private SIPCommander cmder;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Override
public void afterPropertiesSet() throws Exception {
controlMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
// 此处是上级发出的DeviceControl指令
String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
String channelId = getText(rootElement, "DeviceID");
// 远程启动功能
if (!StringUtils.isEmpty(getText(rootElement, "TeleBoot"))) {
if (parentPlatform.getServerGBId().equals(targetGBId)) {
// 远程启动本平台需要在重新启动程序后先对SipStack解绑
logger.info("执行远程启动本平台命令");
cmderFroPlatform.unregister(parentPlatform, null, null);
Thread restartThread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
SipStackImpl stack = (SipStackImpl)up.getSipStack();
stack.stop();
Iterator listener = stack.getListeningPoints();
while (listener.hasNext()) {
stack.deleteListeningPoint((ListeningPoint) listener.next());
}
Iterator providers = stack.getSipProviders();
while (providers.hasNext()) {
stack.deleteSipProvider((SipProvider) providers.next());
}
VManageBootstrap.restart();
} catch (InterruptedException ignored) {
} catch (ObjectInUseException e) {
e.printStackTrace();
}
}
});
restartThread.setDaemon(false);
restartThread.start();
} else {
// 远程启动指定设备
}
}
// 云台/前端控制命令
if (!StringUtils.isEmpty(getText(rootElement,"PTZCmd")) && !parentPlatform.getServerGBId().equals(targetGBId)) {
String cmdString = getText(rootElement,"PTZCmd");
Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);
cmder.fronEndCmd(deviceForPlatform, channelId, cmdString);
}
}
}

View File

@ -0,0 +1,25 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 命令类型 通知命令
* 命令类型 状态信息(心跳)报送, 报警通知, 媒体通知, 移动设备位置数据语音广播通知(TODO), 设备预置位(TODO)
*/
@Component
public class NotifyMessageHandler extends MessageHandlerAbstract implements InitializingBean {
private final String messageType = "Notify";
@Autowired
private MessageRequestProcessor messageRequestProcessor;
@Override
public void afterPropertiesSet() throws Exception {
messageRequestProcessor.addHandler(messageType, this);
}
}

View File

@ -0,0 +1,114 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.service.IDeviceAlarmService;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.GpsUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.RequestEvent;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(AlarmNotifyMessageHandler.class);
private final String cmdType = "Alarm";
@Autowired
private NotifyMessageHandler notifyMessageHandler;
@Autowired
private EventPublisher publisher;
@Autowired
private UserSetup userSetup;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private IDeviceAlarmService deviceAlarmService;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Override
public void afterPropertiesSet() throws Exception {
notifyMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
Element deviceIdElement = rootElement.element("DeviceID");
String channelId = deviceIdElement.getText().toString();
DeviceAlarm deviceAlarm = new DeviceAlarm();
deviceAlarm.setDeviceId(device.getDeviceId());
deviceAlarm.setChannelId(channelId);
deviceAlarm.setAlarmPriority(getText(rootElement, "AlarmPriority"));
deviceAlarm.setAlarmMethod(getText(rootElement, "AlarmMethod"));
deviceAlarm.setAlarmTime(getText(rootElement, "AlarmTime"));
if (getText(rootElement, "AlarmDescription") == null) {
deviceAlarm.setAlarmDescription("");
} else {
deviceAlarm.setAlarmDescription(getText(rootElement, "AlarmDescription"));
}
if (NumericUtil.isDouble(getText(rootElement, "Longitude"))) {
deviceAlarm.setLongitude(Double.parseDouble(getText(rootElement, "Longitude")));
} else {
deviceAlarm.setLongitude(0.00);
}
if (NumericUtil.isDouble(getText(rootElement, "Latitude"))) {
deviceAlarm.setLatitude(Double.parseDouble(getText(rootElement, "Latitude")));
} else {
deviceAlarm.setLatitude(0.00);
}
if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) {
if ( deviceAlarm.getAlarmMethod().equals("4")) {
MobilePosition mobilePosition = new MobilePosition();
mobilePosition.setDeviceId(deviceAlarm.getDeviceId());
mobilePosition.setTime(deviceAlarm.getAlarmTime());
mobilePosition.setLongitude(deviceAlarm.getLongitude());
mobilePosition.setLatitude(deviceAlarm.getLatitude());
mobilePosition.setReportSource("GPS Alarm");
BaiduPoint bp = new BaiduPoint();
bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude()));
logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat());
mobilePosition.setGeodeticSystem("BD-09");
mobilePosition.setCnLng(bp.getBdLng());
mobilePosition.setCnLat(bp.getBdLat());
if (!userSetup.getSavePositionHistory()) {
storager.clearMobilePositionsByDeviceId(device.getDeviceId());
}
storager.insertMobilePosition(mobilePosition);
}
}
logger.debug("存储报警信息、报警分类");
// 存储报警信息报警分类
deviceAlarmService.add(deviceAlarm);
if (offLineDetector.isOnline(device.getDeviceId())) {
publisher.deviceAlarmEventPublish(deviceAlarm);
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

View File

@ -0,0 +1,117 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.List;
@Component
public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(CatalogNotifyMessageHandler.class);
private final String cmdType = "Catalog";
@Autowired
private NotifyMessageHandler notifyMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private SipConfig config;
@Override
public void afterPropertiesSet() throws Exception {
notifyMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + parentPlatform.getServerGBId();
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
try {
// 回复200 OK
responseAck(evt, Response.OK);
Element snElement = rootElement.element("SN");
String sn = snElement.getText();
// 准备回复通道信息
List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
// 查询关联的直播通道
List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
int size = channelReduces.size() + gbStreams.size();
// 回复级联的通道
if (channelReduces.size() > 0) {
for (ChannelReduce channelReduce : channelReduces) {
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
}
}
// 回复直播的通道
if (gbStreams.size() > 0) {
for (GbStream gbStream : gbStreams) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(gbStream.getGbId());
deviceChannel.setName(gbStream.getName());
deviceChannel.setLongitude(gbStream.getLongitude());
deviceChannel.setLatitude(gbStream.getLatitude());
deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
deviceChannel.setManufacture("wvp-pro");
deviceChannel.setStatus(gbStream.isStatus()?1:0);
// deviceChannel.setParentId(parentPlatform.getDeviceGBId());
deviceChannel.setRegisterWay(1);
deviceChannel.setCivilCode(config.getDomain());
deviceChannel.setModel("live");
deviceChannel.setOwner("wvp-pro");
deviceChannel.setParental(0);
deviceChannel.setSecrecy("0");
deviceChannel.setSecrecy("0");
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
}
}
if (size == 0) {
// 回复无通道
cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size);
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,63 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
@Component
public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(KeepaliveNotifyMessageHandler.class);
private final String cmdType = "Keepalive";
@Autowired
private NotifyMessageHandler notifyMessageHandler;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
notifyMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
// 检查设备是否存在并在线 不在线则设置为在线
try {
if (device != null ) {
// 回复200 OK
responseAck(evt, Response.OK);
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
// 不会收到上级平台的心跳信息
}
}

View File

@ -0,0 +1,74 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(MediaStatusNotifyMessageHandler.class);
private final String cmdType = "MediaStatus";
@Autowired
private NotifyMessageHandler notifyMessageHandler;
@Autowired
private SIPCommander cmder;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Override
public void afterPropertiesSet() throws Exception {
notifyMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
// 回复200 OK
try {
responseAck(evt, Response.OK);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
String NotifyType =getText(rootElement, "NotifyType");
if (NotifyType.equals("121")){
logger.info("媒体播放完毕,通知关流");
StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(device.getDeviceId(), "*");
if (streamInfo != null) {
redisCatchStorage.stopPlayback(streamInfo);
cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId());
}
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

View File

@ -0,0 +1,103 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.GpsUtil;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(MobilePositionNotifyMessageHandler.class);
private final String cmdType = "MobilePosition";
@Autowired
private NotifyMessageHandler notifyMessageHandler;
@Autowired
private UserSetup userSetup;
@Autowired
private IVideoManagerStorager storager;
@Override
public void afterPropertiesSet() throws Exception {
notifyMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
try {
rootElement = getRootElement(evt, device.getCharset());
MobilePosition mobilePosition = new MobilePosition();
if (!StringUtils.isEmpty(device.getName())) {
mobilePosition.setDeviceName(device.getName());
}
mobilePosition.setDeviceId(device.getDeviceId());
mobilePosition.setChannelId(getText(rootElement, "DeviceID"));
mobilePosition.setTime(getText(rootElement, "Time"));
mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude")));
mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude")));
if (NumericUtil.isDouble(getText(rootElement, "Speed"))) {
mobilePosition.setSpeed(Double.parseDouble(getText(rootElement, "Speed")));
} else {
mobilePosition.setSpeed(0.0);
}
if (NumericUtil.isDouble(getText(rootElement, "Direction"))) {
mobilePosition.setDirection(Double.parseDouble(getText(rootElement, "Direction")));
} else {
mobilePosition.setDirection(0.0);
}
if (NumericUtil.isDouble(getText(rootElement, "Altitude"))) {
mobilePosition.setAltitude(Double.parseDouble(getText(rootElement, "Altitude")));
} else {
mobilePosition.setAltitude(0.0);
}
mobilePosition.setReportSource("Mobile Position");
BaiduPoint bp = new BaiduPoint();
bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude()));
logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat());
mobilePosition.setGeodeticSystem("BD-09");
mobilePosition.setCnLng(bp.getBdLng());
mobilePosition.setCnLat(bp.getBdLat());
if (!userSetup.getSavePositionHistory()) {
storager.clearMobilePositionsByDeviceId(device.getDeviceId());
}
storager.insertMobilePosition(mobilePosition);
//回复 200 OK
responseAck(evt, Response.OK);
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

View File

@ -0,0 +1,25 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 命令类型 查询指令
* 命令类型 设备状态, 设备目录信息, 设备信息, 文件目录检索(TODO), 报警(TODO), 设备配置(TODO), 设备预置位(TODO), 移动设备位置数据(TODO)
*/
@Component
public class QueryMessageHandler extends MessageHandlerAbstract implements InitializingBean {
private final String messageType = "Query";
@Autowired
private MessageRequestProcessor messageRequestProcessor;
@Override
public void afterPropertiesSet() throws Exception {
messageRequestProcessor.addHandler(messageType, this);
}
}

View File

@ -0,0 +1,77 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.List;
@Component
public class AlarmQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(AlarmQueryMessageHandler.class);
private final String cmdType = "Alarm";
@Autowired
private QueryMessageHandler queryMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private SipConfig config;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
queryMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
logger.info("不支持alarm查询");
try {
responseAck(evt, Response.NOT_FOUND, "not support alarm query");
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,120 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.List;
@Component
public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(CatalogQueryMessageHandler.class);
private final String cmdType = "Catalog";
@Autowired
private QueryMessageHandler queryMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private SipConfig config;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
queryMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + parentPlatform.getServerGBId();
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
try {
// 回复200 OK
responseAck(evt, Response.OK);
Element snElement = rootElement.element("SN");
String sn = snElement.getText();
// 准备回复通道信息
List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
// 查询关联的直播通道
List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
int size = channelReduces.size() + gbStreams.size();
// 回复级联的通道
if (channelReduces.size() > 0) {
for (ChannelReduce channelReduce : channelReduces) {
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
}
}
// 回复直播的通道
if (gbStreams.size() > 0) {
for (GbStream gbStream : gbStreams) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(gbStream.getGbId());
deviceChannel.setName(gbStream.getName());
deviceChannel.setLongitude(gbStream.getLongitude());
deviceChannel.setLatitude(gbStream.getLatitude());
deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
deviceChannel.setManufacture("wvp-pro");
deviceChannel.setStatus(gbStream.isStatus()?1:0);
// deviceChannel.setParentId(parentPlatform.getDeviceGBId());
deviceChannel.setRegisterWay(1);
deviceChannel.setCivilCode(config.getDomain());
deviceChannel.setModel("live");
deviceChannel.setOwner("wvp-pro");
deviceChannel.setParental(0);
deviceChannel.setSecrecy("0");
deviceChannel.setSecrecy("0");
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
}
}
if (size == 0) {
// 回复无通道
cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size);
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,62 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
@Component
public class DeviceInfoQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceInfoQueryMessageHandler.class);
private final String cmdType = "DeviceInfo";
@Autowired
private QueryMessageHandler queryMessageHandler;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Override
public void afterPropertiesSet() throws Exception {
queryMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
logger.info("接收到DeviceInfo查询消息");
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
try {
// 回复200 OK
responseAck(evt, Response.OK);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
String sn = rootElement.element("SN").getText();
cmderFroPlatform.deviceInfoResponse(parentPlatform, sn, fromHeader.getTag());
}
}

View File

@ -0,0 +1,75 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
@Component
public class DeviceStatusQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceStatusQueryMessageHandler.class);
private final String cmdType = "DeviceStatus";
@Autowired
private QueryMessageHandler queryMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private SipConfig config;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
queryMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
logger.info("接收到DeviceStatus查询消息");
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
// 回复200 OK
try {
responseAck(evt, Response.OK);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
String sn = rootElement.element("SN").getText();
cmderFroPlatform.deviceStatusResponse(parentPlatform, sn, fromHeader.getTag());
}
}

View File

@ -0,0 +1,25 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 命令类型 请求动作的应答
* 命令类型 设备控制, 报警通知, 设备目录信息查询, 目录信息查询, 目录收到, 设备信息查询, 设备状态信息查询 ......
*/
@Component
public class ResponseMessageHandler extends MessageHandlerAbstract implements InitializingBean {
private final String messageType = "Response";
@Autowired
private MessageRequestProcessor messageRequestProcessor;
@Override
public void afterPropertiesSet() throws Exception {
messageRequestProcessor.addHandler(messageType, this);
}
}

View File

@ -0,0 +1,58 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.RequestEvent;
@Component
public class AlarmResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(AlarmResponseMessageHandler.class);
private final String cmdType = "Alarm";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
Element deviceIdElement = rootElement.element("DeviceID");
String channelId = deviceIdElement.getText().toString();
String key = DeferredResultHolder.CALLBACK_CMD_ALARM + device.getDeviceId() + channelId;
JSONObject json = new JSONObject();
XmlUtil.node2Json(rootElement, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

View File

@ -0,0 +1,72 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(BroadcastResponseMessageHandler.class);
private final String cmdType = "Broadcast";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
try {
String channelId = getText(rootElement, "DeviceID");
String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + device.getDeviceId() + channelId;
// 回复200 OK
responseAck(evt, Response.OK);
// 此处是对本平台发出Broadcast指令的应答
JSONObject json = new JSONObject();
XmlUtil.node2Json(rootElement, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
} catch (ParseException | SipException | InvalidArgumentException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

View File

@ -0,0 +1,182 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Iterator;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class CatalogResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(CatalogResponseMessageHandler.class);
private final String cmdType = "Catalog";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Autowired
private SipConfig config;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + device.getDeviceId();
Element rootElement = null;
try {
rootElement = getRootElement(evt, device.getCharset());
Element deviceListElement = rootElement.element("DeviceList");
Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
if (deviceListIterator != null) {
// 遍历DeviceList
while (deviceListIterator.hasNext()) {
Element itemDevice = deviceListIterator.next();
Element channelDeviceElement = itemDevice.element("DeviceID");
if (channelDeviceElement == null) {
continue;
}
String channelDeviceId = channelDeviceElement.getText();
Element channdelNameElement = itemDevice.element("Name");
String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : "";
Element statusElement = itemDevice.element("Status");
String status = statusElement != null ? statusElement.getText().toString() : "ON";
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setName(channelName);
deviceChannel.setChannelId(channelDeviceId);
// ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) {
deviceChannel.setStatus(1);
}
if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
deviceChannel.setStatus(0);
}
deviceChannel.setManufacture(getText(itemDevice, "Manufacturer"));
deviceChannel.setModel(getText(itemDevice, "Model"));
deviceChannel.setOwner(getText(itemDevice, "Owner"));
deviceChannel.setCivilCode(getText(itemDevice, "CivilCode"));
deviceChannel.setBlock(getText(itemDevice, "Block"));
deviceChannel.setAddress(getText(itemDevice, "Address"));
if (getText(itemDevice, "Parental") == null || getText(itemDevice, "Parental") == "") {
deviceChannel.setParental(0);
} else {
deviceChannel.setParental(Integer.parseInt(getText(itemDevice, "Parental")));
}
deviceChannel.setParentId(getText(itemDevice, "ParentID"));
if (getText(itemDevice, "SafetyWay") == null || getText(itemDevice, "SafetyWay") == "") {
deviceChannel.setSafetyWay(0);
} else {
deviceChannel.setSafetyWay(Integer.parseInt(getText(itemDevice, "SafetyWay")));
}
if (getText(itemDevice, "RegisterWay") == null || getText(itemDevice, "RegisterWay") == "") {
deviceChannel.setRegisterWay(1);
} else {
deviceChannel.setRegisterWay(Integer.parseInt(getText(itemDevice, "RegisterWay")));
}
deviceChannel.setCertNum(getText(itemDevice, "CertNum"));
if (getText(itemDevice, "Certifiable") == null || getText(itemDevice, "Certifiable") == "") {
deviceChannel.setCertifiable(0);
} else {
deviceChannel.setCertifiable(Integer.parseInt(getText(itemDevice, "Certifiable")));
}
if (getText(itemDevice, "ErrCode") == null || getText(itemDevice, "ErrCode") == "") {
deviceChannel.setErrCode(0);
} else {
deviceChannel.setErrCode(Integer.parseInt(getText(itemDevice, "ErrCode")));
}
deviceChannel.setEndTime(getText(itemDevice, "EndTime"));
deviceChannel.setSecrecy(getText(itemDevice, "Secrecy"));
deviceChannel.setIpAddress(getText(itemDevice, "IPAddress"));
if (getText(itemDevice, "Port") == null || getText(itemDevice, "Port") == "") {
deviceChannel.setPort(0);
} else {
deviceChannel.setPort(Integer.parseInt(getText(itemDevice, "Port")));
}
deviceChannel.setPassword(getText(itemDevice, "Password"));
if (NumericUtil.isDouble(getText(itemDevice, "Longitude"))) {
deviceChannel.setLongitude(Double.parseDouble(getText(itemDevice, "Longitude")));
} else {
deviceChannel.setLongitude(0.00);
}
if (NumericUtil.isDouble(getText(itemDevice, "Latitude"))) {
deviceChannel.setLatitude(Double.parseDouble(getText(itemDevice, "Latitude")));
} else {
deviceChannel.setLatitude(0.00);
}
if (getText(itemDevice, "PTZType") == null || getText(itemDevice, "PTZType") == "") {
deviceChannel.setPTZType(0);
} else {
deviceChannel.setPTZType(Integer.parseInt(getText(itemDevice, "PTZType")));
}
deviceChannel.setHasAudio(true); // 默认含有音频播放时再检查是否有音频及是否AAC
storager.updateChannel(device.getDeviceId(), deviceChannel);
}
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(device);
deferredResultHolder.invokeAllResult(msg);
// 回复200 OK
responseAck(evt, Response.OK);
if (offLineDetector.isOnline(device.getDeviceId())) {
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
}
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (SipException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
}
}

View File

@ -0,0 +1,81 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(ConfigDownloadResponseMessageHandler.class);
private final String cmdType = "ConfigDownload";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private EventPublisher publisher;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
String channelId = getText(element, "DeviceID");
String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + device.getDeviceId() + channelId;
try {
// 回复200 OK
responseAck(evt, Response.OK);
// 此处是对本平台发出DeviceControl指令的应答
JSONObject json = new JSONObject();
XmlUtil.node2Json(element, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
// 不会收到上级平台的心跳信息
}
}

View File

@ -0,0 +1,58 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.RequestEvent;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class DeviceConfigResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceConfigResponseMessageHandler.class);
private final String cmdType = "DeviceConfig";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
JSONObject json = new JSONObject();
XmlUtil.node2Json(element, json);
String channelId = getText(element, "DeviceID");
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + device.getDeviceId() + channelId;
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
}
}

View File

@ -0,0 +1,59 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.RequestEvent;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class DeviceControlResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceControlResponseMessageHandler.class);
private final String cmdType = "DeviceControl";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
// 此处是对本平台发出DeviceControl指令的应答
JSONObject json = new JSONObject();
String channelId = getText(element, "DeviceID");
XmlUtil.node2Json(element, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + device.getDeviceId() + channelId;
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
}
}

View File

@ -0,0 +1,103 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceInfoResponseMessageHandler.class);
private final String cmdType = "DeviceInfo";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Autowired
private SipConfig config;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
logger.debug("接收到DeviceInfo应答消息");
try {
rootElement = getRootElement(evt, device.getCharset());
Element deviceIdElement = rootElement.element("DeviceID");
String channelId = deviceIdElement.getTextTrim();
String key = DeferredResultHolder.CALLBACK_CMD_DEVICEINFO + device.getDeviceId() + channelId;
device.setName(getText(rootElement, "DeviceName"));
device.setManufacturer(getText(rootElement, "Manufacturer"));
device.setModel(getText(rootElement, "Model"));
device.setFirmware(getText(rootElement, "Firmware"));
if (StringUtils.isEmpty(device.getStreamMode())) {
device.setStreamMode("UDP");
}
storager.updateDevice(device);
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(device);
deferredResultHolder.invokeAllResult(msg);
// 回复200 OK
responseAck(evt, Response.OK);
if (offLineDetector.isOnline(device.getDeviceId())) {
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (SipException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
}
}

View File

@ -0,0 +1,89 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
@Component
public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceStatusResponseMessageHandler.class);
private final String cmdType = "DeviceStatus";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
logger.info("接收到DeviceStatus应答消息");
// 检查设备是否存在 不存在则不回复
// 回复200 OK
try {
responseAck(evt, Response.OK);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
Element deviceIdElement = element.element("DeviceID");
String channelId = deviceIdElement.getText();
JSONObject json = new JSONObject();
XmlUtil.node2Json(element, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setKey(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + device.getDeviceId() + channelId);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
if (offLineDetector.isOnline(device.getDeviceId())) {
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
} else {
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
}
}

View File

@ -0,0 +1,103 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.GpsUtil;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class MobilePositionResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(MobilePositionResponseMessageHandler.class);
private final String cmdType = "MobilePosition";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private UserSetup userSetup;
@Autowired
private IVideoManagerStorager storager;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
try {
rootElement = getRootElement(evt, device.getCharset());
MobilePosition mobilePosition = new MobilePosition();
if (!StringUtils.isEmpty(device.getName())) {
mobilePosition.setDeviceName(device.getName());
}
mobilePosition.setDeviceId(device.getDeviceId());
mobilePosition.setChannelId(getText(rootElement, "DeviceID"));
mobilePosition.setTime(getText(rootElement, "Time"));
mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude")));
mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude")));
if (NumericUtil.isDouble(getText(rootElement, "Speed"))) {
mobilePosition.setSpeed(Double.parseDouble(getText(rootElement, "Speed")));
} else {
mobilePosition.setSpeed(0.0);
}
if (NumericUtil.isDouble(getText(rootElement, "Direction"))) {
mobilePosition.setDirection(Double.parseDouble(getText(rootElement, "Direction")));
} else {
mobilePosition.setDirection(0.0);
}
if (NumericUtil.isDouble(getText(rootElement, "Altitude"))) {
mobilePosition.setAltitude(Double.parseDouble(getText(rootElement, "Altitude")));
} else {
mobilePosition.setAltitude(0.0);
}
mobilePosition.setReportSource("Mobile Position");
BaiduPoint bp = new BaiduPoint();
bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude()));
logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat());
mobilePosition.setGeodeticSystem("BD-09");
mobilePosition.setCnLng(bp.getBdLng());
mobilePosition.setCnLat(bp.getBdLat());
if (!userSetup.getSavePositionHistory()) {
storager.clearMobilePositionsByDeviceId(device.getDeviceId());
}
storager.insertMobilePosition(mobilePosition);
//回复 200 OK
responseAck(evt, Response.OK);
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

View File

@ -0,0 +1,151 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
import com.genersoft.iot.vmp.gb28181.bean.RecordItem;
import com.genersoft.iot.vmp.gb28181.transmit.callback.CheckForAllRecordsThread;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(RecordInfoResponseMessageHandler.class);
public static volatile List<String> threadNameList = new ArrayList();
private final String cmdType = "RecordInfo";
private final static String CACHE_RECORDINFO_KEY = "CACHE_RECORDINFO_";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private RedisUtil redis;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
// 回复200 OK
try {
responseAck(evt, Response.OK);
rootElement = getRootElement(evt, device.getCharset());
String uuid = UUID.randomUUID().toString().replace("-", "");
RecordInfo recordInfo = new RecordInfo();
String sn = getText(rootElement, "SN");
String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + device.getDeviceId() + sn;
recordInfo.setDeviceId(device.getDeviceId());
recordInfo.setSn(sn);
recordInfo.setName(getText(rootElement, "Name"));
if (getText(rootElement, "SumNum") == null || getText(rootElement, "SumNum") == "") {
recordInfo.setSumNum(0);
} else {
recordInfo.setSumNum(Integer.parseInt(getText(rootElement, "SumNum")));
}
Element recordListElement = rootElement.element("RecordList");
if (recordListElement == null || recordInfo.getSumNum() == 0) {
logger.info("无录像数据");
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(recordInfo);
deferredResultHolder.invokeAllResult(msg);
} else {
Iterator<Element> recordListIterator = recordListElement.elementIterator();
List<RecordItem> recordList = new ArrayList<RecordItem>();
if (recordListIterator != null) {
RecordItem record = new RecordItem();
logger.info("处理录像列表数据...");
// 遍历DeviceList
while (recordListIterator.hasNext()) {
Element itemRecord = recordListIterator.next();
Element recordElement = itemRecord.element("DeviceID");
if (recordElement == null) {
logger.info("记录为空,下一个...");
continue;
}
record = new RecordItem();
record.setDeviceId(getText(itemRecord, "DeviceID"));
record.setName(getText(itemRecord, "Name"));
record.setFilePath(getText(itemRecord, "FilePath"));
record.setAddress(getText(itemRecord, "Address"));
record.setStartTime(
DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(getText(itemRecord, "StartTime")));
record.setEndTime(
DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(getText(itemRecord, "EndTime")));
record.setSecrecy(itemRecord.element("Secrecy") == null ? 0
: Integer.parseInt(getText(itemRecord, "Secrecy")));
record.setType(getText(itemRecord, "Type"));
record.setRecorderId(getText(itemRecord, "RecorderID"));
recordList.add(record);
}
recordInfo.setRecordList(recordList);
}
// 改用单独线程统计已获取录像文件数量避免多包并行分别统计不完整的问题
String cacheKey = CACHE_RECORDINFO_KEY + device.getDeviceId() + sn;
redis.set(cacheKey + "_" + uuid, recordList, 90);
if (!threadNameList.contains(cacheKey)) {
threadNameList.add(cacheKey);
CheckForAllRecordsThread chk = new CheckForAllRecordsThread(cacheKey, recordInfo);
chk.setName(cacheKey);
chk.setDeferredResultHolder(deferredResultHolder);
chk.setRedis(redis);
chk.setLogger(logger);
chk.start();
if (logger.isDebugEnabled()) {
logger.debug("Start Thread " + cacheKey + ".");
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Thread " + cacheKey + " already started.");
}
}
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

View File

@ -0,0 +1,15 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.response;
import javax.sip.ResponseEvent;
/**
* @description:处理接收IPCamera发来的SIP协议响应消息
* @author: swwheihei
* @date: 2020年5月3日 下午4:42:22
*/
public interface ISIPResponseProcessor {
void process(ResponseEvent evt);
}

View File

@ -0,0 +1,8 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.response;
import org.springframework.beans.factory.InitializingBean;
public abstract class SIPResponseProcessorAbstract implements InitializingBean, ISIPResponseProcessor {
}

View File

@ -0,0 +1,48 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.SipLayer;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.ResponseEvent;
/**
* @description: BYE请求响应器
* @author: swwheihei
* @date: 2020年5月3日 下午5:32:05
*/
@Component
public class ByeResponseProcessor extends SIPResponseProcessorAbstract {
private String method = "BYE";
@Autowired
private SipLayer sipLayer;
@Autowired
private SipConfig config;
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addResponseProcessor(method, this);
}
/**
* 处理BYE响应
*
* @param evt
*/
@Override
public void process(ResponseEvent evt) {
// TODO Auto-generated method stub
}
}

View File

@ -0,0 +1,47 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.SipLayer;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.ResponseEvent;
/**
* @description: CANCEL响应处理器
* @author: panlinlin
* @date: 2021年11月5日 16:35
*/
@Component
public class CancelResponseProcessor extends SIPResponseProcessorAbstract {
private String method = "CANCEL";
@Autowired
private SipLayer sipLayer;
@Autowired
private SipConfig config;
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addResponseProcessor(method, this);
}
/**
* 处理CANCEL响应
*
* @param evt
*/
@Override
public void process(ResponseEvent evt) {
// TODO Auto-generated method stub
}
}

View File

@ -1,75 +1,97 @@
package com.genersoft.iot.vmp.gb28181.transmit.response.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl;
import java.text.ParseException; import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.SipLayer;
import javax.sip.*; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import javax.sip.address.SipURI; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import javax.sip.header.CSeqHeader; import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract;
import javax.sip.message.Request; import gov.nist.javax.sip.ResponseEventExt;
import javax.sip.message.Response; import gov.nist.javax.sip.stack.SIPDialog;
import org.slf4j.Logger;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import org.slf4j.LoggerFactory;
import gov.nist.javax.sip.ResponseEventExt; import org.springframework.beans.factory.annotation.Autowired;
import gov.nist.javax.sip.stack.SIPDialog; import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.sip.InvalidArgumentException;
import org.springframework.beans.factory.annotation.Autowired; import javax.sip.ResponseEvent;
import org.springframework.stereotype.Component; import javax.sip.SipException;
import javax.sip.address.SipURI;
import com.genersoft.iot.vmp.conf.SipConfig; import javax.sip.header.CSeqHeader;
import com.genersoft.iot.vmp.gb28181.SipLayer; import javax.sip.message.Request;
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; import javax.sip.message.Response;
import java.text.ParseException;
/**
* @Description:处理INVITE响应 /**
* @author: swwheihei * @description: 处理INVITE响应
* @date: 2020年5月3日 下午4:43:52 * @author: panlinlin
*/ * @date: 2021年11月5日 1640
@Component */
public class InviteResponseProcessor implements ISIPResponseProcessor { @Component
public class InviteResponseProcessor extends SIPResponseProcessorAbstract {
private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class);
private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class);
@Autowired private String method = "INVITE";
private VideoStreamSessionManager streamSession;
@Autowired
/** private SipLayer sipLayer;
* 处理invite响应
* @Autowired
* @param evt 响应消息 private SipConfig config;
* @throws ParseException
*/
@Override @Autowired
public void process(ResponseEvent evt, SipLayer layer, SipConfig config) throws ParseException { private SIPProcessorObserver sipProcessorObserver;
try {
Response response = evt.getResponse(); @Override
int statusCode = response.getStatusCode(); public void afterPropertiesSet() throws Exception {
// trying不会回复 // 添加消息处理的订阅
if (statusCode == Response.TRYING) { sipProcessorObserver.addResponseProcessor(method, this);
} }
// 成功响应
// 下发ack @Autowired
if (statusCode == Response.OK) { private VideoStreamSessionManager streamSession;
ResponseEventExt event = (ResponseEventExt)evt;
SIPDialog dialog = (SIPDialog)evt.getDialog(); /**
CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME); * 处理invite响应
Request reqAck = dialog.createAck(cseq.getSeqNumber()); *
SipURI requestURI = (SipURI) reqAck.getRequestURI(); * @param evt 响应消息
requestURI.setHost(event.getRemoteIpAddress()); * @throws ParseException
requestURI.setPort(event.getRemotePort()); */
reqAck.setRequestURI(requestURI); @Override
logger.info("" + event.getRemoteIpAddress() + ":" + event.getRemotePort() + "回复ack"); public void process(ResponseEvent evt ){
SipURI sipURI = (SipURI)dialog.getRemoteParty().getURI(); try {
String deviceId = requestURI.getUser(); Response response = evt.getResponse();
String channelId = sipURI.getUser(); int statusCode = response.getStatusCode();
// trying不会回复
dialog.sendAck(reqAck); if (statusCode == Response.TRYING) {
}
} // 成功响应
} catch (InvalidArgumentException | SipException e) { // 下发ack
e.printStackTrace(); if (statusCode == Response.OK) {
} ResponseEventExt event = (ResponseEventExt)evt;
} SIPDialog dialog = (SIPDialog)evt.getDialog();
CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
} Request reqAck = dialog.createAck(cseq.getSeqNumber());
SipURI requestURI = (SipURI) reqAck.getRequestURI();
try {
requestURI.setHost(event.getRemoteIpAddress());
} catch (ParseException e) {
e.printStackTrace();
}
requestURI.setPort(event.getRemotePort());
reqAck.setRequestURI(requestURI);
logger.info("" + event.getRemoteIpAddress() + ":" + event.getRemotePort() + "回复ack");
SipURI sipURI = (SipURI)dialog.getRemoteParty().getURI();
String deviceId = requestURI.getUser();
String channelId = sipURI.getUser();
dialog.sendAck(reqAck);
}
} catch (InvalidArgumentException | SipException e) {
e.printStackTrace();
}
}
}

View File

@ -1,11 +1,10 @@
package com.genersoft.iot.vmp.gb28181.transmit.response.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.SipLayer;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -19,14 +18,15 @@ import javax.sip.header.WWWAuthenticateHeader;
import javax.sip.message.Response; import javax.sip.message.Response;
/** /**
* @Description:Register响应处理器 * @description:Register响应处理器
* @author: swwheihei * @author: swwheihei
* @date: 2020年5月3日 下午5:32:23 * @date: 2020年5月3日 下午5:32:23
*/ */
@Component @Component
public class RegisterResponseProcessor implements ISIPResponseProcessor { public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
private Logger logger = LoggerFactory.getLogger(RegisterResponseProcessor.class); private Logger logger = LoggerFactory.getLogger(RegisterResponseProcessor.class);
private String method = "REGISTER";
@Autowired @Autowired
private ISIPCommanderForPlatform sipCommanderForPlatform; private ISIPCommanderForPlatform sipCommanderForPlatform;
@ -37,18 +37,22 @@ public class RegisterResponseProcessor implements ISIPResponseProcessor {
@Autowired @Autowired
private IRedisCatchStorage redisCatchStorage; private IRedisCatchStorage redisCatchStorage;
public RegisterResponseProcessor() { @Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addResponseProcessor(method, this);
} }
/** /**
* 处理Register响应 * 处理Register响应
* *
* @param evt * @param evt 事件
* @param layer
* @param config
*/ */
@Override @Override
public void process(ResponseEvent evt, SipLayer layer, SipConfig config) { public void process(ResponseEvent evt) {
Response response = evt.getResponse(); Response response = evt.getResponse();
CallIdHeader callIdHeader = (CallIdHeader) response.getHeader(CallIdHeader.NAME); CallIdHeader callIdHeader = (CallIdHeader) response.getHeader(CallIdHeader.NAME);
String callId = callIdHeader.getCallId(); String callId = callIdHeader.getCallId();

View File

@ -0,0 +1,7 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.timeout;
import javax.sip.TimeoutEvent;
public interface ITimeoutProcessor {
void process(TimeoutEvent event);
}

View File

@ -0,0 +1,36 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.timeout.impl;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.timeout.ITimeoutProcessor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.TimeoutEvent;
import javax.sip.header.CallIdHeader;
@Component
public class TimeoutProcessorImpl implements InitializingBean, ITimeoutProcessor {
@Autowired
private SIPProcessorObserver processorObserver;
@Autowired
private SipSubscribe sipSubscribe;
@Override
public void afterPropertiesSet() throws Exception {
processorObserver.addTimeoutProcessor(this);
}
@Override
public void process(TimeoutEvent event) {
// TODO Auto-generated method stub
CallIdHeader callIdHeader = event.getClientTransaction().getDialog().getCallId();
String callId = callIdHeader.getCallId();
SipSubscribe.Event errorSubscribe = sipSubscribe.getErrorSubscribe(callId);
SipSubscribe.EventResult<TimeoutEvent> timeoutEventEventResult = new SipSubscribe.EventResult<>(event);
errorSubscribe.response(timeoutEventEventResult);
}
}

View File

@ -1,12 +0,0 @@
package com.genersoft.iot.vmp.gb28181.transmit.request;
/**
* @Description:处理接收IPCamera发来的SIP协议请求消息
* @author: swwheihei
* @date: 2020年5月3日 下午4:42:22
*/
public interface ISIPRequestProcessor {
public void process();
}

View File

@ -1,131 +0,0 @@
package com.genersoft.iot.vmp.gb28181.transmit.request;
import javax.sip.PeerUnavailableException;
import javax.sip.RequestEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipFactory;
import javax.sip.SipProvider;
import javax.sip.TransactionAlreadyExistsException;
import javax.sip.TransactionUnavailableException;
import javax.sip.address.AddressFactory;
import javax.sip.header.HeaderFactory;
import javax.sip.header.ViaHeader;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import gov.nist.javax.sip.SipStackImpl;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.stack.SIPServerTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Description:处理接收IPCamera发来的SIP协议请求消息
* @author: songww
* @date: 2020年5月3日 下午4:42:22
*/
public abstract class SIPRequestAbstractProcessor implements ISIPRequestProcessor {
private final static Logger logger = LoggerFactory.getLogger(SIPRequestAbstractProcessor.class);
protected RequestEvent evt;
private SipProvider tcpSipProvider;
private SipProvider udpSipProvider;
@Override
public void process() {
this.process(evt);
}
public abstract void process(RequestEvent evt);
public ServerTransaction getServerTransaction(RequestEvent evt) {
Request request = evt.getRequest();
ServerTransaction serverTransaction = evt.getServerTransaction();
// 判断TCP还是UDP
boolean isTcp = false;
ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
String transport = reqViaHeader.getTransport();
if (transport.equals("TCP")) {
isTcp = true;
}
if (serverTransaction == null) {
try {
if (isTcp) {
SipStackImpl stack = (SipStackImpl)tcpSipProvider.getSipStack();
serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true);
if (serverTransaction == null) {
serverTransaction = tcpSipProvider.getNewServerTransaction(request);
}
} else {
SipStackImpl stack = (SipStackImpl)udpSipProvider.getSipStack();
serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true);
if (serverTransaction == null) {
serverTransaction = udpSipProvider.getNewServerTransaction(request);
}
}
} catch (TransactionAlreadyExistsException e) {
logger.error(e.getMessage());
} catch (TransactionUnavailableException e) {
logger.error(e.getMessage());
}
}
return serverTransaction;
}
public AddressFactory getAddressFactory() {
try {
return SipFactory.getInstance().createAddressFactory();
} catch (PeerUnavailableException e) {
e.printStackTrace();
}
return null;
}
public HeaderFactory getHeaderFactory() {
try {
return SipFactory.getInstance().createHeaderFactory();
} catch (PeerUnavailableException e) {
e.printStackTrace();
}
return null;
}
public MessageFactory getMessageFactory() {
try {
return SipFactory.getInstance().createMessageFactory();
} catch (PeerUnavailableException e) {
e.printStackTrace();
}
return null;
}
public RequestEvent getRequestEvent() {
return evt;
}
public void setRequestEvent(RequestEvent evt) {
this.evt = evt;
}
public SipProvider getTcpSipProvider() {
return tcpSipProvider;
}
public void setTcpSipProvider(SipProvider tcpSipProvider) {
this.tcpSipProvider = tcpSipProvider;
}
public SipProvider getUdpSipProvider() {
return udpSipProvider;
}
public void setUdpSipProvider(SipProvider udpSipProvider) {
this.udpSipProvider = udpSipProvider;
}
}

View File

@ -1,28 +0,0 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import javax.sip.RequestEvent;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
/**
* @Description:CANCEL请求处理器
* @author: swwheihei
* @date: 2020年5月3日 下午5:32:23
*/
public class CancelRequestProcessor extends SIPRequestAbstractProcessor {
/**
* 处理CANCEL请求
*
* @param evt
* @param layer
* @param transaction
* @param config
*/
@Override
public void process(RequestEvent evt) {
// TODO 优先级99 Cancel Request消息实现此消息一般为级联消息上级给下级发送请求取消指令
}
}

View File

@ -1,31 +0,0 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import javax.sip.RequestEvent;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Description:暂不支持的消息请求处理器
* @author: swwheihei
* @date: 2020年5月3日 下午5:32:59
*/
public class OtherRequestProcessor extends SIPRequestAbstractProcessor {
private Logger logger = LoggerFactory.getLogger(OtherRequestProcessor.class);
/**
* <p>Title: process</p>
* <p>Description: </p>
* @param evt
* @param layer
* @param transaction
* @param config
*/
@Override
public void process(RequestEvent evt) {
logger.info("Unsupported the method: " + evt.getRequest().getMethod());
}
}

View File

@ -1,19 +0,0 @@
package com.genersoft.iot.vmp.gb28181.transmit.response;
import java.text.ParseException;
import javax.sip.ResponseEvent;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.SipLayer;
/**
* @Description:处理接收IPCamera发来的SIP协议响应消息
* @author: swwheihei
* @date: 2020年5月3日 下午4:42:22
*/
public interface ISIPResponseProcessor {
public void process(ResponseEvent evt, SipLayer layer, SipConfig config) throws ParseException;
}

Some files were not shown because too many files have changed in this diff Show More