Browse Source
# Conflicts: # src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java # src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java # src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java # src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java # src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java # src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java # src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java # src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java # src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java # src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java # src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java # src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java # src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java # src/main/resources/application-dev.ymlpull/76/head

53 changed files with 7144 additions and 7160 deletions
@ -1,23 +1,21 @@ |
|||||
package com.genersoft.iot.vmp; |
package com.genersoft.iot.vmp; |
||||
|
|
||||
import java.util.logging.LogManager; |
import org.springframework.boot.SpringApplication; |
||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
import org.springframework.boot.SpringApplication; |
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|
||||
import org.springframework.context.ConfigurableApplicationContext; |
@SpringBootApplication |
||||
|
public class VManageBootstrap extends LogManager { |
||||
@SpringBootApplication |
private static String[] args; |
||||
public class VManageBootstrap extends LogManager { |
private static ConfigurableApplicationContext context; |
||||
private static String[] args; |
public static void main(String[] args) { |
||||
private static ConfigurableApplicationContext context; |
VManageBootstrap.args = args; |
||||
public static void main(String[] args) { |
VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); |
||||
VManageBootstrap.args = args; |
} |
||||
VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); |
// 项目重启
|
||||
} |
public static void restart() { |
||||
// 项目重启
|
context.close(); |
||||
public static void restart() { |
VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); |
||||
context.close(); |
|
||||
VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); |
} |
||||
|
} |
||||
} |
|
||||
} |
|
||||
|
@ -1,46 +1,48 @@ |
|||||
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 MEDIA_SERVER_PREFIX = "VMP_media_server"; |
public static final String MEDIA_SERVER_PREFIX = "VMP_media_server"; |
||||
|
|
||||
public static final String MEDIA_STREAM_PREFIX = "VMP_media_stream"; |
public static final String MEDIA_STREAM_PREFIX = "VMP_media_stream"; |
||||
|
|
||||
public static final String DEVICE_PREFIX = "VMP_device_"; |
public static final String DEVICE_PREFIX = "VMP_device_"; |
||||
|
|
||||
public static final String CACHEKEY_PREFIX = "VMP_channel_"; |
public static final String CACHEKEY_PREFIX = "VMP_channel_"; |
||||
|
|
||||
public static final String KEEPLIVEKEY_PREFIX = "VMP_keeplive_"; |
public static final String KEEPLIVEKEY_PREFIX = "VMP_keeplive_"; |
||||
|
|
||||
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 PLATFORM_PREFIX = "VMP_platform"; |
public static final String PLATFORM_PREFIX = "VMP_platform"; |
||||
|
|
||||
public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_platform_keeplive_"; |
public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_platform_keeplive_"; |
||||
|
|
||||
public static final String PLATFORM_CATCH_PREFIX = "VMP_platform_catch_"; |
public static final String PLATFORM_CATCH_PREFIX = "VMP_platform_catch_"; |
||||
|
|
||||
public static final String PLATFORM_REGISTER_PREFIX = "VMP_platform_register_"; |
public static final String PLATFORM_REGISTER_PREFIX = "VMP_platform_register_"; |
||||
|
|
||||
public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_platform_register_info_"; |
public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_platform_register_info_"; |
||||
|
|
||||
public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_platform_send_rtp_info_"; |
public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_platform_send_rtp_info_"; |
||||
|
|
||||
public static final String Pattern_Topic = "VMP_keeplive_platform_"; |
public static final String Pattern_Topic = "VMP_keeplive_platform_"; |
||||
|
|
||||
public static final String EVENT_ONLINE_REGISTER = "1"; |
public static final String EVENT_ONLINE_REGISTER = "1"; |
||||
|
|
||||
public static final String EVENT_ONLINE_KEEPLIVE = "2"; |
public static final String EVENT_ONLINE_KEEPLIVE = "2"; |
||||
|
|
||||
public static final String EVENT_OUTLINE_UNREGISTER = "1"; |
public static final String EVENT_OUTLINE_UNREGISTER = "1"; |
||||
|
|
||||
public static final String EVENT_OUTLINE_TIMEOUT = "2"; |
public static final String EVENT_OUTLINE_TIMEOUT = "2"; |
||||
} |
|
||||
|
public static final String MEDIA_SSRC_USED_PREFIX = "VMP_media_used_ssrc_"; |
||||
|
} |
||||
|
@ -1,63 +1,58 @@ |
|||||
package com.genersoft.iot.vmp.conf; |
package com.genersoft.iot.vmp.conf; |
||||
|
|
||||
|
import com.genersoft.iot.vmp.common.VideoManagerConstants; |
||||
|
import com.genersoft.iot.vmp.utils.redis.JedisUtil; |
||||
import org.slf4j.Logger; |
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
import org.slf4j.LoggerFactory; |
||||
import org.springframework.beans.factory.annotation.Value; |
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.CommandLineRunner; |
import org.springframework.boot.CommandLineRunner; |
||||
import org.springframework.core.annotation.Order; |
import org.springframework.core.annotation.Order; |
||||
import org.springframework.stereotype.Component; |
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.Set; |
||||
|
|
||||
|
|
||||
/** |
/** |
||||
* 对配置文件进行校验 |
* 对配置文件进行校验 |
||||
*/ |
*/ |
||||
@Component |
@Component |
||||
@Order(value=2) |
@Order(value = 0) |
||||
public class ApplicationCheckRunner implements CommandLineRunner { |
public class ApplicationCheckRunner implements CommandLineRunner { |
||||
|
|
||||
private Logger logger = LoggerFactory.getLogger("ApplicationCheckRunner"); |
private Logger logger = LoggerFactory.getLogger("ApplicationCheckRunner"); |
||||
|
@Autowired |
||||
@Value("${sip.ip}") |
SipConfig sipConfig; |
||||
private String sipIp; |
@Autowired |
||||
|
MediaConfig mediaConfig; |
||||
@Value("${media.ip}") |
@Autowired |
||||
private String mediaIp; |
JedisUtil jedisUtil; |
||||
|
|
||||
@Value("${media.wanIp}") |
|
||||
private String mediaWanIp; |
|
||||
|
|
||||
@Value("${media.hookIp}") |
|
||||
private String mediaHookIp; |
|
||||
|
|
||||
@Value("${media.port}") |
|
||||
private int mediaPort; |
|
||||
|
|
||||
@Value("${media.secret}") |
|
||||
private String mediaSecret; |
|
||||
|
|
||||
@Value("${media.streamNoneReaderDelayMS}") |
|
||||
private String streamNoneReaderDelayMS; |
|
||||
|
|
||||
@Value("${sip.ip}") |
|
||||
private String sipIP; |
|
||||
|
|
||||
@Value("${server.port}") |
|
||||
private String serverPort; |
|
||||
|
|
||||
@Value("${media.autoConfig}") |
|
||||
private boolean autoConfig; |
|
||||
|
|
||||
|
|
||||
@Override |
@Override |
||||
public void run(String... args) throws Exception { |
public void run(String... args) { |
||||
if (sipIP.equals("localhost") || sipIP.equals("127.0.0.1")) { |
String sipIp = sipConfig.getSipIp(); |
||||
logger.error("sip.ip不能使用 {} ,请使用类似192.168.1.44这样的来自网卡的IP!!!", sipIP ); |
if (sipIp.equals("localhost") || sipIp.equals("127.0.0.1")) { |
||||
|
logger.error("sip.ip不能使用 {} ,请使用类似192.168.1.44这样的来自网卡的IP!!!", sipIp); |
||||
System.exit(1); |
System.exit(1); |
||||
} |
} |
||||
|
String mediaIp = mediaConfig.getMediaIp(); |
||||
if (mediaIp.equals("localhost") || mediaIp.equals("127.0.0.1")) { |
String[] mediaIpArr = mediaIp.split(","); |
||||
logger.warn("mediaIp.ip使用 {} ,将无法收到网络内其他设备的推流!!!", mediaIp ); |
mediaConfig.setMediaIpArr(mediaIpArr); |
||||
|
|
||||
|
for (String mId : mediaIpArr) { |
||||
|
if (mId.equals("localhost") || mId.equals("127.0.0.1")) { |
||||
|
logger.warn("mediaIp.ip使用localhost或127.0.0.1,将无法收到网络内其他设备的推流!!!"); |
||||
|
} |
||||
} |
} |
||||
|
|
||||
|
HashMap mediaServerSsrcMap = new HashMap<>(mediaIpArr.length); |
||||
|
for (int i = 0; i < mediaIpArr.length; i++) { |
||||
|
String mIp = mediaIpArr[i]; |
||||
|
SsrcConfig ssrcConfig = new SsrcConfig(); |
||||
|
Set<String> usedSet = jedisUtil.smembers(VideoManagerConstants.MEDIA_SSRC_USED_PREFIX + mIp); |
||||
|
ssrcConfig.init(mIp, usedSet); |
||||
|
mediaServerSsrcMap.put(mIp, ssrcConfig); |
||||
|
} |
||||
|
mediaConfig.setMediaServerSsrcMap(mediaServerSsrcMap); |
||||
} |
} |
||||
} |
} |
||||
|
@ -0,0 +1,53 @@ |
|||||
|
package com.genersoft.iot.vmp.conf; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 对配置文件进行校验 |
||||
|
*/ |
||||
|
@Configuration("mediaConfig") |
||||
|
@Data |
||||
|
public class MediaConfig { |
||||
|
@Value("${media.ip}") |
||||
|
private String mediaIp; |
||||
|
private String[] mediaIpArr; |
||||
|
|
||||
|
@Value("${media.hookIp}") |
||||
|
private String mediaHookIp; |
||||
|
|
||||
|
@Value("${media.port}") |
||||
|
private Integer mediaPort; |
||||
|
|
||||
|
@Value("${media.autoConfig}") |
||||
|
private Boolean autoConfig; |
||||
|
|
||||
|
@Value("${media.secret}") |
||||
|
private String mediaSecret; |
||||
|
|
||||
|
@Value("${media.streamNoneReaderDelayMS}") |
||||
|
private String streamNoneReaderDelayMS; |
||||
|
|
||||
|
@Value("${media.autoApplyPlay}") |
||||
|
private Boolean autoApplyPlay; |
||||
|
|
||||
|
@Value("${media.seniorSdp}") |
||||
|
private Boolean seniorSdp; |
||||
|
|
||||
|
@Value("${media.rtp.enable}") |
||||
|
private Boolean rtpEnable; |
||||
|
|
||||
|
@Value("${media.rtp.udpPortRange}") |
||||
|
private String udpPortRange; |
||||
|
|
||||
|
/** |
||||
|
* 每一台ZLM都有一套独立的SSRC列表 |
||||
|
* 在ApplicationCheckRunner里对mediaServerSsrcMap进行初始化 |
||||
|
*/ |
||||
|
private HashMap<String, SsrcConfig> mediaServerSsrcMap; |
||||
|
|
||||
|
} |
@ -1,57 +1,89 @@ |
|||||
package com.genersoft.iot.vmp.conf; |
package com.genersoft.iot.vmp.conf; |
||||
|
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport; |
import com.alibaba.fastjson.parser.ParserConfig; |
||||
import org.springframework.context.annotation.Bean; |
import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer; |
||||
import org.springframework.context.annotation.Configuration; |
import org.apache.commons.lang3.StringUtils; |
||||
import org.springframework.data.redis.connection.RedisConnectionFactory; |
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.data.redis.core.RedisTemplate; |
import org.springframework.cache.annotation.CachingConfigurerSupport; |
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer; |
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.data.redis.serializer.StringRedisSerializer; |
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory; |
||||
import com.alibaba.fastjson.parser.ParserConfig; |
import org.springframework.data.redis.core.RedisTemplate; |
||||
import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer; |
import org.springframework.data.redis.listener.RedisMessageListenerContainer; |
||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer; |
||||
/** |
import redis.clients.jedis.JedisPool; |
||||
* @Description:Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置 |
import redis.clients.jedis.JedisPoolConfig; |
||||
* @author: swwheihei |
|
||||
* @date: 2019年5月30日 上午10:58:25 |
/** |
||||
* |
* @Description:Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置 |
||||
*/ |
* @author: swwheihei |
||||
@Configuration |
* @date: 2019年5月30日 上午10:58:25 |
||||
public class RedisConfig extends CachingConfigurerSupport { |
*/ |
||||
|
@Configuration |
||||
@Bean("redisTemplate") |
public class RedisConfig extends CachingConfigurerSupport { |
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { |
|
||||
RedisTemplate<Object, Object> template = new RedisTemplate<>(); |
@Value("${spring.redis.host}") |
||||
template.setConnectionFactory(redisConnectionFactory); |
private String host; |
||||
// 使用fastjson进行序列化处理,提高解析效率
|
@Value("${spring.redis.port}") |
||||
FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<Object>(Object.class); |
private int port; |
||||
// value值的序列化采用fastJsonRedisSerializer
|
@Value("${spring.redis.database}") |
||||
template.setValueSerializer(serializer); |
private int database; |
||||
template.setHashValueSerializer(serializer); |
@Value("${spring.redis.password}") |
||||
// key的序列化采用StringRedisSerializer
|
private String password; |
||||
template.setKeySerializer(new StringRedisSerializer()); |
@Value("${spring.redis.timeout}") |
||||
template.setHashKeySerializer(new StringRedisSerializer()); |
private int timeout; |
||||
template.setConnectionFactory(redisConnectionFactory); |
@Value("${spring.redis.poolMaxTotal}") |
||||
// 使用fastjson时需设置此项,否则会报异常not support type
|
private int poolMaxTotal; |
||||
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); |
@Value("${spring.redis.poolMaxIdle}") |
||||
return template; |
private int poolMaxIdle; |
||||
} |
@Value("${spring.redis.poolMaxWait}") |
||||
|
private int poolMaxWait; |
||||
/** |
|
||||
* redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器 |
@Bean |
||||
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理 |
public JedisPool jedisPool() { |
||||
* |
if (StringUtils.isBlank(password)) { |
||||
* @param connectionFactory |
password = null; |
||||
* @param listenerAdapter |
} |
||||
* @return |
JedisPoolConfig poolConfig = new JedisPoolConfig(); |
||||
*/ |
poolConfig.setMaxIdle(poolMaxIdle); |
||||
@Bean |
poolConfig.setMaxTotal(poolMaxTotal); |
||||
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) { |
// 秒转毫秒
|
||||
|
poolConfig.setMaxWaitMillis(poolMaxWait * 1000); |
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer(); |
JedisPool jp = new JedisPool(poolConfig, host, port, timeout * 1000, password, database); |
||||
container.setConnectionFactory(connectionFactory); |
return jp; |
||||
return container; |
} |
||||
} |
|
||||
|
@Bean("redisTemplate") |
||||
} |
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { |
||||
|
RedisTemplate<Object, Object> template = new RedisTemplate<>(); |
||||
|
template.setConnectionFactory(redisConnectionFactory); |
||||
|
// 使用fastjson进行序列化处理,提高解析效率
|
||||
|
FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<Object>(Object.class); |
||||
|
// value值的序列化采用fastJsonRedisSerializer
|
||||
|
template.setValueSerializer(serializer); |
||||
|
template.setHashValueSerializer(serializer); |
||||
|
// key的序列化采用StringRedisSerializer
|
||||
|
template.setKeySerializer(new StringRedisSerializer()); |
||||
|
template.setHashKeySerializer(new StringRedisSerializer()); |
||||
|
template.setConnectionFactory(redisConnectionFactory); |
||||
|
// 使用fastjson时需设置此项,否则会报异常not support type
|
||||
|
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); |
||||
|
return template; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器 |
||||
|
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理 |
||||
|
* |
||||
|
* @param connectionFactory |
||||
|
* @return |
||||
|
*/ |
||||
|
@Bean |
||||
|
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) { |
||||
|
|
||||
|
RedisMessageListenerContainer container = new RedisMessageListenerContainer(); |
||||
|
container.setConnectionFactory(connectionFactory); |
||||
|
return container; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
@ -0,0 +1,51 @@ |
|||||
|
package com.genersoft.iot.vmp.conf; |
||||
|
|
||||
|
import com.genersoft.iot.vmp.utils.ConfigConst; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.Set; |
||||
|
|
||||
|
/** |
||||
|
* 每一个zlm流媒体服务器,都设置MAX_STRTEAM_COUNT个可用同步信源(SSRC) |
||||
|
*/ |
||||
|
@Data |
||||
|
public class SsrcConfig { |
||||
|
/** |
||||
|
* zlm流媒体服务器IP |
||||
|
*/ |
||||
|
String mediaServerIp; |
||||
|
/** |
||||
|
* zlm流媒体服务器已用会话句柄 |
||||
|
*/ |
||||
|
private List<String> isUsed; |
||||
|
/** |
||||
|
* zlm流媒体服务器可用会话句柄 |
||||
|
*/ |
||||
|
private List<String> notUsed; |
||||
|
|
||||
|
public void init(String mediaServerIp, Set<String> usedSet) { |
||||
|
this.mediaServerIp = mediaServerIp; |
||||
|
this.isUsed = new ArrayList<>(); |
||||
|
|
||||
|
this.notUsed = new ArrayList<>(); |
||||
|
for (int i = 1; i < ConfigConst.MAX_STRTEAM_COUNT; i++) { |
||||
|
String ssrc; |
||||
|
if (i < 10) { |
||||
|
ssrc = "000" + i; |
||||
|
} else if (i < 100) { |
||||
|
ssrc = "00" + i; |
||||
|
} else if (i < 1000) { |
||||
|
ssrc = "0" + i; |
||||
|
} else { |
||||
|
ssrc = String.valueOf(i); |
||||
|
} |
||||
|
if (null == usedSet || !usedSet.contains(ssrc)) { |
||||
|
this.notUsed.add(ssrc); |
||||
|
} else { |
||||
|
this.isUsed.add(ssrc); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,236 +1,260 @@ |
|||||
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 com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
||||
import java.util.TooManyListenersException; |
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorFactory; |
||||
import java.util.concurrent.LinkedBlockingQueue; |
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; |
||||
import java.util.concurrent.ThreadPoolExecutor; |
import gov.nist.javax.sip.SipStackImpl; |
||||
import java.util.concurrent.TimeUnit; |
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
import javax.sip.*; |
import org.springframework.beans.factory.annotation.Autowired; |
||||
import javax.sip.header.CallIdHeader; |
import org.springframework.context.annotation.Bean; |
||||
import javax.sip.message.Response; |
import org.springframework.context.annotation.DependsOn; |
||||
|
import org.springframework.stereotype.Component; |
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
|
||||
import org.slf4j.Logger; |
import javax.sip.*; |
||||
import org.slf4j.LoggerFactory; |
import javax.sip.header.CallIdHeader; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
import javax.sip.message.Response; |
||||
import org.springframework.context.annotation.Bean; |
import java.text.ParseException; |
||||
// import org.springframework.context.annotation.ComponentScan;
|
import java.util.Properties; |
||||
import org.springframework.context.annotation.DependsOn; |
import java.util.TooManyListenersException; |
||||
import org.springframework.stereotype.Component; |
import java.util.concurrent.LinkedBlockingQueue; |
||||
|
import java.util.concurrent.ThreadPoolExecutor; |
||||
import com.genersoft.iot.vmp.conf.SipConfig; |
import java.util.concurrent.TimeUnit; |
||||
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorFactory; |
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; |
@Component |
||||
|
public class SipLayer implements SipListener { |
||||
import gov.nist.javax.sip.SipStackImpl; |
|
||||
|
private final static Logger logger = LoggerFactory.getLogger(SipLayer.class); |
||||
@Component |
|
||||
public class SipLayer implements SipListener { |
@Autowired |
||||
|
private SipConfig sipConfig; |
||||
private final static Logger logger = LoggerFactory.getLogger(SipLayer.class); |
|
||||
|
@Autowired |
||||
@Autowired |
private SIPProcessorFactory processorFactory; |
||||
private SipConfig sipConfig; |
|
||||
|
@Autowired |
||||
@Autowired |
private SipSubscribe sipSubscribe; |
||||
private SIPProcessorFactory processorFactory; |
|
||||
|
private SipStack sipStack; |
||||
@Autowired |
|
||||
private SipSubscribe sipSubscribe; |
private SipFactory sipFactory; |
||||
|
|
||||
private SipStack sipStack; |
/** |
||||
|
* 消息处理器线程池 |
||||
private SipFactory sipFactory; |
*/ |
||||
|
private ThreadPoolExecutor processThreadPool; |
||||
/** |
|
||||
* 消息处理器线程池 |
@Bean("initSipServer") |
||||
*/ |
private ThreadPoolExecutor initSipServer() { |
||||
private ThreadPoolExecutor processThreadPool; |
|
||||
|
int processThreadNum = Runtime.getRuntime().availableProcessors() * 10; |
||||
@Bean("initSipServer") |
LinkedBlockingQueue<Runnable> processQueue = new LinkedBlockingQueue<>(10000); |
||||
private ThreadPoolExecutor initSipServer() { |
processThreadPool = new ThreadPoolExecutor(processThreadNum, processThreadNum, |
||||
|
0L, TimeUnit.MILLISECONDS, processQueue, |
||||
int processThreadNum = Runtime.getRuntime().availableProcessors() * 10; |
new ThreadPoolExecutor.CallerRunsPolicy()); |
||||
LinkedBlockingQueue<Runnable> processQueue = new LinkedBlockingQueue<Runnable>(10000); |
return processThreadPool; |
||||
processThreadPool = new ThreadPoolExecutor(processThreadNum,processThreadNum, |
} |
||||
0L,TimeUnit.MILLISECONDS,processQueue, |
|
||||
new ThreadPoolExecutor.CallerRunsPolicy()); |
@Bean("sipFactory") |
||||
return processThreadPool; |
@DependsOn("initSipServer") |
||||
} |
private SipFactory createSipFactory() { |
||||
|
sipFactory = SipFactory.getInstance(); |
||||
@Bean("sipFactory") |
sipFactory.setPathName("gov.nist"); |
||||
@DependsOn("initSipServer") |
return sipFactory; |
||||
private SipFactory createSipFactory() { |
} |
||||
sipFactory = SipFactory.getInstance(); |
|
||||
sipFactory.setPathName("gov.nist"); |
@Bean("sipStack") |
||||
return sipFactory; |
@DependsOn({"initSipServer", "sipFactory"}) |
||||
} |
private SipStack createSipStack() throws PeerUnavailableException { |
||||
|
Properties properties = new Properties(); |
||||
@Bean("sipStack") |
properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); |
||||
@DependsOn({"initSipServer", "sipFactory"}) |
properties.setProperty("javax.sip.IP_ADDRESS", sipConfig.getSipIp()); |
||||
private SipStack createSipStack() throws PeerUnavailableException { |
properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "false"); |
||||
Properties properties = new Properties(); |
/** |
||||
properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); |
* sip_server_log.log 和 sip_debug_log.log public static final int TRACE_NONE = |
||||
properties.setProperty("javax.sip.IP_ADDRESS", sipConfig.getSipIp()); |
* 0; public static final int TRACE_MESSAGES = 16; public static final int |
||||
properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "false"); |
* TRACE_EXCEPTION = 17; public static final int TRACE_DEBUG = 32; |
||||
/** |
*/ |
||||
* sip_server_log.log 和 sip_debug_log.log public static final int TRACE_NONE = |
properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "0"); |
||||
* 0; public static final int TRACE_MESSAGES = 16; public static final int |
properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "sip_server_log"); |
||||
* TRACE_EXCEPTION = 17; public static final int TRACE_DEBUG = 32; |
properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "sip_debug_log"); |
||||
*/ |
sipStack = (SipStackImpl) sipFactory.createSipStack(properties); |
||||
properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "0"); |
return sipStack; |
||||
properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "sip_server_log"); |
} |
||||
properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "sip_debug_log"); |
|
||||
sipStack = (SipStackImpl) sipFactory.createSipStack(properties); |
@Bean("tcpSipProvider") |
||||
return sipStack; |
@DependsOn("sipStack") |
||||
} |
private SipProvider startTcpListener() { |
||||
|
ListeningPoint tcpListeningPoint = null; |
||||
@Bean("tcpSipProvider") |
SipProvider tcpSipProvider = null; |
||||
@DependsOn("sipStack") |
try { |
||||
private SipProvider startTcpListener() { |
tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getSipIp(), sipConfig.getSipPort(), "TCP"); |
||||
ListeningPoint tcpListeningPoint = null; |
} catch (TransportNotSupportedException e) { |
||||
SipProvider tcpSipProvider = null; |
logger.error("创建SIP服务失败!", e); |
||||
try { |
System.exit(1); |
||||
tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getSipIp(), sipConfig.getSipPort(), "TCP"); |
} catch (InvalidArgumentException e) { |
||||
tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint); |
if ("Cannot assign requested address: JVM_Bind".equals(e.getMessage())) { |
||||
tcpSipProvider.addSipListener(this); |
logger.error("创建SIP服务失败,请检查sip.ip必须是本地网卡上的IP!", e); |
||||
logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getSipPort() + "}"); |
} else { |
||||
} catch (TransportNotSupportedException | InvalidArgumentException | TooManyListenersException | ObjectInUseException e) { |
logger.error("创建SIP服务失败!", e); |
||||
logger.error(String.format("创建SIP服务失败: %s", e.getMessage())); |
} |
||||
} |
System.exit(1); |
||||
return tcpSipProvider; |
} |
||||
} |
try { |
||||
|
tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint); |
||||
@Bean("udpSipProvider") |
} catch (ObjectInUseException e) { |
||||
@DependsOn("sipStack") |
logger.error("创建SIP服务失败!", e); |
||||
private SipProvider startUdpListener() throws Exception { |
System.exit(1); |
||||
ListeningPoint udpListeningPoint = sipStack.createListeningPoint(sipConfig.getSipIp(), sipConfig.getSipPort(), "UDP"); |
} |
||||
SipProvider udpSipProvider = sipStack.createSipProvider(udpListeningPoint); |
try { |
||||
udpSipProvider.addSipListener(this); |
tcpSipProvider.addSipListener(this); |
||||
logger.info("Sip Server UDP 启动成功 port {" + sipConfig.getSipPort() + "}"); |
} catch (TooManyListenersException e) { |
||||
return udpSipProvider; |
logger.error("创建SIP服务失败!", e); |
||||
} |
System.exit(1); |
||||
|
} |
||||
/** |
logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getSipPort() + "}"); |
||||
* SIP服务端接收消息的方法 Content 里面是GBK编码 This method is called by the SIP stack when a |
return tcpSipProvider; |
||||
* new request arrives. |
|
||||
*/ |
|
||||
@Override |
// try {
|
||||
public void processRequest(RequestEvent evt) { |
// tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getSipIp(), sipConfig.getSipPort(), "TCP");
|
||||
logger.debug(evt.getRequest().toString()); |
// tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint);
|
||||
// 由于jainsip是单线程程序,为提高性能并发处理
|
// tcpSipProvider.addSipListener(this);
|
||||
processThreadPool.execute(() -> { |
// logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getSipPort() + "}");
|
||||
if (processorFactory != null) { |
// } catch (TransportNotSupportedException | InvalidArgumentException | TooManyListenersException | ObjectInUseException e) {
|
||||
processorFactory.createRequestProcessor(evt).process(); |
// logger.error(String.format("创建SIP服务失败: %s", e.getMessage()));
|
||||
} |
// }
|
||||
}); |
// return tcpSipProvider;
|
||||
} |
} |
||||
|
|
||||
@Override |
@Bean("udpSipProvider") |
||||
public void processResponse(ResponseEvent evt) { |
@DependsOn("sipStack") |
||||
Response response = evt.getResponse(); |
private SipProvider startUdpListener() throws Exception { |
||||
logger.debug(evt.getResponse().toString()); |
ListeningPoint udpListeningPoint = sipStack.createListeningPoint(sipConfig.getSipIp(), sipConfig.getSipPort(), "UDP"); |
||||
int status = response.getStatusCode(); |
SipProvider udpSipProvider = sipStack.createSipProvider(udpListeningPoint); |
||||
if (((status >= 200) && (status < 300)) || status == 401) { // Success!
|
udpSipProvider.addSipListener(this); |
||||
ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt); |
logger.info("Sip Server UDP 启动成功 port {" + sipConfig.getSipPort() + "}"); |
||||
try { |
return udpSipProvider; |
||||
processor.process(evt, this, sipConfig); |
} |
||||
} catch (ParseException e) { |
|
||||
// TODO Auto-generated catch block
|
/** |
||||
e.printStackTrace(); |
* SIP服务端接收消息的方法 Content 里面是GBK编码 This method is called by the SIP stack when a |
||||
} |
* new request arrives. |
||||
if (evt.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) { |
*/ |
||||
CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME); |
@Override |
||||
if (callIdHeader != null) { |
public void processRequest(RequestEvent evt) { |
||||
SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId()); |
logger.debug(evt.getRequest().toString()); |
||||
if (subscribe != null) { |
// 由于jainsip是单线程程序,为提高性能并发处理
|
||||
subscribe.response(evt); |
processThreadPool.execute(() -> { |
||||
} |
if (processorFactory != null) { |
||||
} |
processorFactory.createRequestProcessor(evt).process(); |
||||
} |
} |
||||
} else if ((status >= 100) && (status < 200)) { |
}); |
||||
// 增加其它无需回复的响应,如101、180等
|
} |
||||
} else { |
|
||||
logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/); |
@Override |
||||
if (evt.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) { |
public void processResponse(ResponseEvent evt) { |
||||
CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME); |
Response response = evt.getResponse(); |
||||
if (callIdHeader != null) { |
logger.debug(evt.getResponse().toString()); |
||||
SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()); |
int status = response.getStatusCode(); |
||||
if (subscribe != null) { |
if (((status >= 200) && (status < 300)) || status == 401) { // Success!
|
||||
subscribe.response(evt); |
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()); |
||||
* <p> |
if (subscribe != null) { |
||||
* Title: processTimeout |
subscribe.response(evt); |
||||
* </p> |
} |
||||
* <p> |
} |
||||
* Description: |
} |
||||
* </p> |
} else if ((status >= 100) && (status < 200)) { |
||||
* |
// 增加其它无需回复的响应,如101、180等
|
||||
* @param timeoutEvent |
} else { |
||||
*/ |
logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/); |
||||
@Override |
if (evt.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) { |
||||
public void processTimeout(TimeoutEvent timeoutEvent) { |
CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME); |
||||
// TODO Auto-generated method stub
|
if (callIdHeader != null) { |
||||
|
SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()); |
||||
} |
if (subscribe != null) { |
||||
|
subscribe.response(evt); |
||||
/** |
} |
||||
* <p> |
} |
||||
* Title: processIOException |
} |
||||
* </p> |
} |
||||
* <p> |
|
||||
* Description: |
|
||||
* </p> |
} |
||||
* |
|
||||
* @param exceptionEvent |
/** |
||||
*/ |
* <p> |
||||
@Override |
* Title: processTimeout |
||||
public void processIOException(IOExceptionEvent exceptionEvent) { |
* </p> |
||||
// TODO Auto-generated method stub
|
* <p> |
||||
|
* Description: |
||||
} |
* </p> |
||||
|
* |
||||
/** |
* @param timeoutEvent |
||||
* <p> |
*/ |
||||
* Title: processTransactionTerminated |
@Override |
||||
* </p> |
public void processTimeout(TimeoutEvent timeoutEvent) { |
||||
* <p> |
// TODO Auto-generated method stub
|
||||
* Description: |
|
||||
* </p> |
} |
||||
* |
|
||||
* @param transactionTerminatedEvent |
/** |
||||
*/ |
* <p> |
||||
@Override |
* Title: processIOException |
||||
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) { |
* </p> |
||||
// TODO Auto-generated method stub
|
* <p> |
||||
|
* Description: |
||||
} |
* </p> |
||||
|
* |
||||
/** |
* @param exceptionEvent |
||||
* <p> |
*/ |
||||
* Title: processDialogTerminated |
@Override |
||||
* </p> |
public void processIOException(IOExceptionEvent exceptionEvent) { |
||||
* <p> |
// TODO Auto-generated method stub
|
||||
* Description: |
|
||||
* </p> |
} |
||||
* |
|
||||
* @param dialogTerminatedEvent |
/** |
||||
*/ |
* <p> |
||||
@Override |
* Title: processTransactionTerminated |
||||
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) { |
* </p> |
||||
// TODO Auto-generated method stub
|
* <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
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
@ -1,55 +1,53 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.bean; |
package com.genersoft.iot.vmp.gb28181.bean; |
||||
|
|
||||
|
|
||||
//import gov.nist.javax.sip.header.SIPDate;
|
import java.util.List; |
||||
|
|
||||
import java.util.List; |
/** |
||||
|
* @Description:设备录像信息bean |
||||
/** |
* @author: swwheihei |
||||
* @Description:设备录像信息bean |
* @date: 2020年5月8日 下午2:05:56 |
||||
* @author: swwheihei |
*/ |
||||
* @date: 2020年5月8日 下午2:05:56 |
public class RecordInfo { |
||||
*/ |
|
||||
public class RecordInfo { |
private String deviceId; |
||||
|
|
||||
private String deviceId; |
private String name; |
||||
|
|
||||
private String name; |
private int sumNum; |
||||
|
|
||||
private int sumNum; |
private List<RecordItem> recordList; |
||||
|
|
||||
private List<RecordItem> recordList; |
public String getDeviceId() { |
||||
|
return deviceId; |
||||
public String getDeviceId() { |
} |
||||
return deviceId; |
|
||||
} |
public void setDeviceId(String deviceId) { |
||||
|
this.deviceId = deviceId; |
||||
public void setDeviceId(String deviceId) { |
} |
||||
this.deviceId = deviceId; |
|
||||
} |
public String getName() { |
||||
|
return name; |
||||
public String getName() { |
} |
||||
return name; |
|
||||
} |
public void setName(String name) { |
||||
|
this.name = name; |
||||
public void setName(String name) { |
} |
||||
this.name = name; |
|
||||
} |
public int getSumNum() { |
||||
|
return sumNum; |
||||
public int getSumNum() { |
} |
||||
return sumNum; |
|
||||
} |
public void setSumNum(int sumNum) { |
||||
|
this.sumNum = sumNum; |
||||
public void setSumNum(int sumNum) { |
} |
||||
this.sumNum = sumNum; |
|
||||
} |
public List<RecordItem> getRecordList() { |
||||
|
return recordList; |
||||
public List<RecordItem> getRecordList() { |
} |
||||
return recordList; |
|
||||
} |
public void setRecordList(List<RecordItem> recordList) { |
||||
|
this.recordList = recordList; |
||||
public void setRecordList(List<RecordItem> recordList) { |
} |
||||
this.recordList = recordList; |
|
||||
} |
} |
||||
|
|
||||
} |
|
||||
|
@ -1,24 +1,24 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.event; |
package com.genersoft.iot.vmp.gb28181.event; |
||||
|
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.stereotype.Component; |
import org.springframework.stereotype.Component; |
||||
|
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants; |
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 |
||||
*/ |
*/ |
||||
@Component |
@Component |
||||
public class DeviceOffLineDetector { |
public class DeviceOffLineDetector { |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private RedisUtil redis; |
private RedisUtil redis; |
||||
|
|
||||
public boolean isOnline(String deviceId) { |
public Boolean isOnline(String deviceId) { |
||||
String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + deviceId; |
String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + deviceId; |
||||
return redis.hasKey(key); |
return redis.hasKey(key); |
||||
} |
} |
||||
} |
} |
||||
|
@ -0,0 +1,23 @@ |
|||||
|
package com.genersoft.iot.vmp.gb28181.session; |
||||
|
|
||||
|
public enum PlayTypeEnum { |
||||
|
|
||||
|
PLAY("0", "直播"), |
||||
|
PLAY_BACK("1", "回放"); |
||||
|
|
||||
|
private String value; |
||||
|
private String name; |
||||
|
|
||||
|
PlayTypeEnum(String value, String name) { |
||||
|
this.value = value; |
||||
|
this.name = name; |
||||
|
} |
||||
|
|
||||
|
public String getValue() { |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
public String getName() { |
||||
|
return name; |
||||
|
} |
||||
|
} |
@ -1,93 +0,0 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.session; |
|
||||
|
|
||||
import java.util.ArrayList; |
|
||||
import java.util.List; |
|
||||
import java.util.Random; |
|
||||
|
|
||||
import com.genersoft.iot.vmp.conf.SipConfig; |
|
||||
import com.genersoft.iot.vmp.utils.SpringBeanFactory; |
|
||||
|
|
||||
/** |
|
||||
* @Description:SIP信令中的SSRC工具类。SSRC值由10位十进制整数组成的字符串,第一位为0代表实况,为1则代表回放;第二位至第六位由监控域ID的第4位到第8位组成;最后4位为不重复的4个整数 |
|
||||
* @author: swwheihei |
|
||||
* @date: 2020年5月10日 上午11:57:57 |
|
||||
*/ |
|
||||
public class SsrcUtil { |
|
||||
|
|
||||
private static String ssrcPrefix; |
|
||||
|
|
||||
private static List<String> isUsed; |
|
||||
|
|
||||
private static List<String> notUsed; |
|
||||
|
|
||||
private static void init() { |
|
||||
SipConfig sipConfig = (SipConfig) SpringBeanFactory.getBean("sipConfig"); |
|
||||
ssrcPrefix = sipConfig.getSipDomain().substring(3, 8); |
|
||||
isUsed = new ArrayList<String>(); |
|
||||
notUsed = new ArrayList<String>(); |
|
||||
for (int i = 1; i < 10000; i++) { |
|
||||
if (i < 10) { |
|
||||
notUsed.add("000" + i); |
|
||||
} else if (i < 100) { |
|
||||
notUsed.add("00" + i); |
|
||||
} else if (i < 1000) { |
|
||||
notUsed.add("0" + i); |
|
||||
} else { |
|
||||
notUsed.add(String.valueOf(i)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取视频预览的SSRC值,第一位固定为0 |
|
||||
* |
|
||||
*/ |
|
||||
public static String getPlaySsrc() { |
|
||||
return "0" + getSsrcPrefix() + getSN(); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取录像回放的SSRC值,第一位固定为1 |
|
||||
* |
|
||||
*/ |
|
||||
public static String getPlayBackSsrc() { |
|
||||
return "1" + getSsrcPrefix() + getSN(); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 释放ssrc,主要用完的ssrc一定要释放,否则会耗尽 |
|
||||
* |
|
||||
*/ |
|
||||
public static void releaseSsrc(String ssrc) { |
|
||||
String sn = ssrc.substring(6); |
|
||||
isUsed.remove(sn); |
|
||||
notUsed.add(sn); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取后四位数SN,随机数 |
|
||||
* |
|
||||
*/ |
|
||||
private static String getSN() { |
|
||||
String sn = null; |
|
||||
int index = 0; |
|
||||
if (notUsed.size() == 0) { |
|
||||
throw new RuntimeException("ssrc已经用完"); |
|
||||
} else if (notUsed.size() == 1) { |
|
||||
sn = notUsed.get(0); |
|
||||
} else { |
|
||||
index = new Random().nextInt(notUsed.size() - 1); |
|
||||
sn = notUsed.get(index); |
|
||||
} |
|
||||
notUsed.remove(index); |
|
||||
isUsed.add(sn); |
|
||||
return sn; |
|
||||
} |
|
||||
|
|
||||
private static String getSsrcPrefix() { |
|
||||
if (ssrcPrefix == null) { |
|
||||
init(); |
|
||||
} |
|
||||
return ssrcPrefix; |
|
||||
} |
|
||||
} |
|
@ -1,42 +1,285 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.session; |
package com.genersoft.iot.vmp.gb28181.session; |
||||
|
|
||||
import java.util.concurrent.ConcurrentHashMap; |
import com.genersoft.iot.vmp.common.StreamInfo; |
||||
|
import com.genersoft.iot.vmp.common.VideoManagerConstants; |
||||
import javax.sip.ClientTransaction; |
import com.genersoft.iot.vmp.conf.MediaConfig; |
||||
|
import com.genersoft.iot.vmp.conf.MediaServerConfig; |
||||
import org.springframework.stereotype.Component; |
import com.genersoft.iot.vmp.conf.SipConfig; |
||||
|
import com.genersoft.iot.vmp.conf.SsrcConfig; |
||||
/** |
import com.genersoft.iot.vmp.gb28181.bean.Device; |
||||
* @Description:视频流session管理器,管理视频预览、预览回放的通信句柄 |
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
||||
* @author: swwheihei |
import com.genersoft.iot.vmp.utils.redis.JedisUtil; |
||||
* @date: 2020年5月13日 下午4:03:02 |
import lombok.extern.slf4j.Slf4j; |
||||
*/ |
import org.apache.commons.lang3.StringUtils; |
||||
@Component |
import org.springframework.beans.factory.annotation.Autowired; |
||||
public class VideoStreamSessionManager { |
import org.springframework.stereotype.Component; |
||||
|
|
||||
private ConcurrentHashMap<String, ClientTransaction> sessionMap = new ConcurrentHashMap<>(); |
import javax.annotation.PostConstruct; |
||||
private ConcurrentHashMap<String, String> ssrcMap = new ConcurrentHashMap<>(); |
import javax.sip.ClientTransaction; |
||||
|
import java.util.List; |
||||
public String createPlaySsrc(){ |
import java.util.Map; |
||||
return SsrcUtil.getPlaySsrc(); |
import java.util.Random; |
||||
} |
import java.util.Set; |
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
public String createPlayBackSsrc(){ |
|
||||
return SsrcUtil.getPlayBackSsrc(); |
/** |
||||
} |
* @Description:视频流session管理器,管理视频预览、预览回放的通信句柄 |
||||
|
* @author: swwheihei |
||||
public void put(String streamId,String ssrc,ClientTransaction transaction){ |
* @date: 2020年5月13日 下午4:03:02 |
||||
sessionMap.put(streamId, transaction); |
*/ |
||||
ssrcMap.put(streamId, ssrc); |
@Slf4j |
||||
} |
@Component |
||||
|
public class VideoStreamSessionManager { |
||||
public ClientTransaction get(String streamId){ |
/** |
||||
return sessionMap.get(streamId); |
* key: ssrc 播流会话句柄(streamId)和同步信源(SSRC)的对应关系 |
||||
} |
* value: 流媒体服务器 |
||||
|
*/ |
||||
public void remove(String streamId) { |
private ConcurrentHashMap<String, ClientTransaction> sessionMap = new ConcurrentHashMap<>(); |
||||
sessionMap.remove(streamId); |
private String ssrcPrefix; |
||||
SsrcUtil.releaseSsrc(ssrcMap.get(streamId)); |
|
||||
ssrcMap.remove(streamId); |
@Autowired |
||||
} |
private SipConfig sipConfig; |
||||
} |
@Autowired |
||||
|
private MediaConfig mediaConfig; |
||||
|
@Autowired |
||||
|
private JedisUtil jedisUtil; |
||||
|
@Autowired |
||||
|
private IRedisCatchStorage redisCatchStorage; |
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init() { |
||||
|
this.ssrcPrefix = sipConfig.getSipDomain().substring(3, 8); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取视频预览的会话信息。 |
||||
|
*/ |
||||
|
public StreamInfo createPlayStreamInfo(Device device, String channelId) { |
||||
|
// SSRC值,第一位固定为0
|
||||
|
StreamInfo streamInfo = createStreamInfo(device, channelId, PlayTypeEnum.PLAY); |
||||
|
// 会话句柄和ZLM服务器的对应关系,存到redis,防止服务器宕机数据丢失。
|
||||
|
redisCatchStorage.startPlay(streamInfo); |
||||
|
return streamInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取录像回放的会话信息 |
||||
|
* 会话句柄和ZLM服务器的对应关系,存到redis,防止服务器宕机数据丢失 |
||||
|
*/ |
||||
|
public StreamInfo createPlayBackStreamInfo(Device device, String channelId) { |
||||
|
// SSRC值,第一位固定为1
|
||||
|
StreamInfo streamInfo = createStreamInfo(device, channelId, PlayTypeEnum.PLAY_BACK); |
||||
|
// 会话句柄和ZLM服务器的对应关系,存到redis,防止服务器宕机数据丢失。
|
||||
|
redisCatchStorage.startPlayback(streamInfo); |
||||
|
return streamInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 1、选举ZLM服务器 |
||||
|
* 2、分配SSRC |
||||
|
* 3、生成streamId和播流RUL,如果此时未连接ZLM,会抛出运行时异常 |
||||
|
* 4、已分配SSRC存储到redis,防止服务器宕机后数据丢失。 |
||||
|
*/ |
||||
|
private StreamInfo createStreamInfo(Device device, String channelId, PlayTypeEnum playType) { |
||||
|
// 1、选举ZLM服务器
|
||||
|
SsrcConfig ssrcConfig = elect(); |
||||
|
List<String> isUsed = ssrcConfig.getIsUsed(); |
||||
|
List<String> notUsed = ssrcConfig.getNotUsed(); |
||||
|
|
||||
|
// 2、分配SSRC
|
||||
|
String sn; |
||||
|
int index = 0; |
||||
|
if (notUsed.size() == 0) { |
||||
|
throw new RuntimeException("ssrc已经用完"); |
||||
|
} else if (notUsed.size() == 1) { |
||||
|
sn = notUsed.get(0); |
||||
|
} else { |
||||
|
index = new Random().nextInt(notUsed.size() - 1); |
||||
|
sn = notUsed.get(index); |
||||
|
} |
||||
|
String ssrc = playType.getValue() + ssrcPrefix + sn; |
||||
|
String mediaServerIp = ssrcConfig.getMediaServerIp(); |
||||
|
|
||||
|
// 3、生成streamId和播流RUL,如果此时未连接ZLM,会抛出运行时异常
|
||||
|
StreamInfo streamInfo = initStreamInfo(device, channelId, ssrc, mediaServerIp); |
||||
|
|
||||
|
// 4、已分配SSRC存储到redis,防止服务器宕机后数据丢失。
|
||||
|
jedisUtil.sadd(VideoManagerConstants.MEDIA_SSRC_USED_PREFIX + mediaServerIp, sn); |
||||
|
notUsed.remove(index); |
||||
|
isUsed.add(sn); |
||||
|
return streamInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 流媒体服务器选举算法 |
||||
|
* |
||||
|
* @return |
||||
|
*/ |
||||
|
private SsrcConfig elect() { |
||||
|
Set<Map.Entry<String, SsrcConfig>> entries = mediaConfig.getMediaServerSsrcMap().entrySet(); |
||||
|
SsrcConfig min = null; |
||||
|
for (Map.Entry<String, SsrcConfig> e : entries) { |
||||
|
SsrcConfig vo = e.getValue(); |
||||
|
if (null == min) { |
||||
|
min = vo; |
||||
|
continue; |
||||
|
} |
||||
|
if (vo.getNotUsed().size() > min.getNotUsed().size()) { |
||||
|
min = vo; |
||||
|
} |
||||
|
} |
||||
|
return min; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 生成streamId和播流RUL,如果此时未连接ZLM,会抛出运行时异常 |
||||
|
* |
||||
|
* @param device |
||||
|
* @param channelId |
||||
|
* @param ssrc |
||||
|
* @param mediaServerIp |
||||
|
* @return |
||||
|
*/ |
||||
|
private StreamInfo initStreamInfo(Device device, String channelId, String ssrc, String mediaServerIp) { |
||||
|
String streamId; |
||||
|
if (ssrc.startsWith(PlayTypeEnum.PLAY.getValue()) && mediaConfig.getRtpEnable()) { |
||||
|
streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId); |
||||
|
} else { |
||||
|
streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); |
||||
|
} |
||||
|
StreamInfo streamInfo = new StreamInfo(); |
||||
|
streamInfo.setMediaServerIp(mediaServerIp); |
||||
|
streamInfo.setSsrc(ssrc); |
||||
|
streamInfo.setStreamId(streamId); |
||||
|
streamInfo.setDeviceID(device.getDeviceId()); |
||||
|
streamInfo.setChannelId(channelId); |
||||
|
MediaServerConfig mediaServerConfig = redisCatchStorage.getMediaInfo(); |
||||
|
if (null == mediaServerConfig) { |
||||
|
throw new RuntimeException("点播时发现ZLM尚未连接..."); |
||||
|
} |
||||
|
|
||||
|
streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerIp, mediaServerConfig.getHttpPort(), streamId)); |
||||
|
streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaServerIp, mediaServerConfig.getHttpPort(), streamId)); |
||||
|
|
||||
|
streamInfo.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaServerIp, mediaServerConfig.getHttpPort(), streamId)); |
||||
|
streamInfo.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaServerIp, mediaServerConfig.getHttpPort(), streamId)); |
||||
|
|
||||
|
streamInfo.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaServerIp, mediaServerConfig.getHttpPort(), streamId)); |
||||
|
streamInfo.setWs_hls(String.format("ws://%s:%s/rtp/%s/hls.m3u8", mediaServerIp, mediaServerConfig.getHttpPort(), streamId)); |
||||
|
|
||||
|
streamInfo.setTs(String.format("http://%s:%s/rtp/%s.live.ts", mediaServerIp, mediaServerConfig.getHttpPort(), streamId)); |
||||
|
streamInfo.setWs_ts(String.format("ws://%s:%s/rtp/%s.live.ts", mediaServerIp, mediaServerConfig.getHttpPort(), streamId)); |
||||
|
|
||||
|
streamInfo.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaServerIp, mediaServerConfig.getRtmpPort(), streamId)); |
||||
|
streamInfo.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaServerIp, mediaServerConfig.getRtspPort(), streamId)); |
||||
|
|
||||
|
return streamInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查找IPC通道播流使用流媒体服务器的IP |
||||
|
* |
||||
|
* @param channelId |
||||
|
* @param streamId |
||||
|
* @return |
||||
|
*/ |
||||
|
public String getMediaServerIp(String channelId, String streamId) { |
||||
|
StreamInfo streamInfo = this.getStreamInfo(channelId, streamId); |
||||
|
return null == streamInfo ? null : streamInfo.getMediaServerIp(); |
||||
|
} |
||||
|
|
||||
|
public StreamInfo getPlayStreamInfo(String channelId) { |
||||
|
if (StringUtils.isBlank(channelId)) { |
||||
|
log.error("getPlayStreamInfo channelId can not be null!!!"); |
||||
|
return null; |
||||
|
} |
||||
|
return redisCatchStorage.queryPlayByChannel(channelId); |
||||
|
} |
||||
|
|
||||
|
public StreamInfo getPlayBackStreamInfo(String channelId) { |
||||
|
if (StringUtils.isBlank(channelId)) { |
||||
|
log.error("getPlayBackStreamInfo channelId can not be null!!!"); |
||||
|
return null; |
||||
|
} |
||||
|
return redisCatchStorage.queryPlaybackByChannel(channelId); |
||||
|
} |
||||
|
|
||||
|
public StreamInfo getStreamInfo(String channelId, String streamId) { |
||||
|
if (StringUtils.isBlank(channelId) || StringUtils.isBlank(streamId)) { |
||||
|
log.error("getStreamInfo channelId and streamId can not be null!!!"); |
||||
|
return null; |
||||
|
} |
||||
|
StreamInfo streamInfo = getStreamInfo(channelId, streamId, PlayTypeEnum.PLAY); |
||||
|
if (null == streamInfo) { |
||||
|
streamInfo = getStreamInfo(channelId, streamId, PlayTypeEnum.PLAY_BACK); |
||||
|
} |
||||
|
return streamInfo; |
||||
|
} |
||||
|
|
||||
|
private StreamInfo getStreamInfo(String channelId, String streamId, PlayTypeEnum playType) { |
||||
|
if (StringUtils.isBlank(channelId) || StringUtils.isBlank(streamId)) { |
||||
|
log.error("getStreamInfo channelId and streamId can not be null!!!"); |
||||
|
return null; |
||||
|
} |
||||
|
// TODO channelId
|
||||
|
if (null == playType || PlayTypeEnum.PLAY.equals(playType)) { |
||||
|
return redisCatchStorage.queryPlayByStreamId(channelId, streamId); |
||||
|
} else { |
||||
|
return redisCatchStorage.queryPlaybackByStreamId(channelId, streamId); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 存储会话 |
||||
|
* |
||||
|
* @param channelId |
||||
|
* @param streamId |
||||
|
* @param transaction |
||||
|
*/ |
||||
|
public void putClientTransaction(String channelId, String streamId, ClientTransaction transaction) { |
||||
|
String streamKey = getStreamKey(channelId, streamId); |
||||
|
sessionMap.put(streamKey, transaction); |
||||
|
} |
||||
|
|
||||
|
public ClientTransaction getClientTransaction(String channelId, String streamId) { |
||||
|
String streamKey = getStreamKey(channelId, streamId); |
||||
|
return sessionMap.get(streamKey); |
||||
|
} |
||||
|
|
||||
|
public void remove(String channelId, String streamId) { |
||||
|
StreamInfo streamInfo = this.getStreamInfo(channelId, streamId); |
||||
|
if (null == streamId) { |
||||
|
return; |
||||
|
} |
||||
|
this.remove(streamInfo); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 移除会话并释放ssrc,主要用完的ssrc一定要释放,否则会耗尽 |
||||
|
*/ |
||||
|
public void remove(StreamInfo streamInfo) { |
||||
|
String streamKey = getStreamKey(streamInfo.getChannelId(), streamInfo.getStreamId()); |
||||
|
// 移除会话
|
||||
|
sessionMap.remove(streamKey); |
||||
|
|
||||
|
String ssrc = streamInfo.getSsrc(); |
||||
|
String sn = ssrc.substring(6); |
||||
|
String mediaServerIp = streamInfo.getMediaServerIp(); |
||||
|
// 释放ssrc,并从redis移除
|
||||
|
jedisUtil.srem(VideoManagerConstants.MEDIA_SSRC_USED_PREFIX + mediaServerIp, sn); |
||||
|
SsrcConfig ssrcConfig = mediaConfig.getMediaServerSsrcMap().get(mediaServerIp); |
||||
|
ssrcConfig.getIsUsed().remove(sn); |
||||
|
ssrcConfig.getNotUsed().add(sn); |
||||
|
|
||||
|
// 会话句柄和ZLM服务器的对应关系,从redis移除
|
||||
|
if (ssrc.startsWith(PlayTypeEnum.PLAY.getValue())) { |
||||
|
redisCatchStorage.stopPlay(streamInfo); |
||||
|
} else { |
||||
|
redisCatchStorage.stopPlayback(streamInfo); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static String getStreamKey(String channelId, String streamId) { |
||||
|
return channelId + "_" + streamId; |
||||
|
} |
||||
|
} |
||||
|
@ -1,231 +1,231 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.transmit; |
package com.genersoft.iot.vmp.gb28181.transmit; |
||||
|
|
||||
import javax.sip.RequestEvent; |
import javax.sip.RequestEvent; |
||||
import javax.sip.ResponseEvent; |
import javax.sip.ResponseEvent; |
||||
import javax.sip.SipProvider; |
import javax.sip.SipProvider; |
||||
import javax.sip.header.CSeqHeader; |
import javax.sip.header.CSeqHeader; |
||||
import javax.sip.message.Request; |
import javax.sip.message.Request; |
||||
import javax.sip.message.Response; |
import javax.sip.message.Response; |
||||
|
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
||||
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*; |
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*; |
||||
import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
||||
// 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; |
||||
import org.springframework.context.annotation.Lazy; |
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.conf.SipConfig; |
||||
import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler; |
import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler; |
||||
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.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.ISIPRequestProcessor; |
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.AckRequestProcessor; |
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.ByeRequestProcessor; |
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.CancelRequestProcessor; |
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.InviteRequestProcessor; |
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.MessageRequestProcessor; |
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.NotifyRequestProcessor; |
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.OtherRequestProcessor; |
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor; |
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.request.impl.SubscribeRequestProcessor; |
||||
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; |
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.ByeResponseProcessor; |
||||
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.CancelResponseProcessor; |
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.InviteResponseProcessor; |
||||
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.OtherResponseProcessor; |
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.OtherResponseProcessor; |
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
||||
import com.genersoft.iot.vmp.utils.SpringBeanFactory; |
import com.genersoft.iot.vmp.utils.SpringBeanFactory; |
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
||||
|
|
||||
/** |
/** |
||||
* @Description: SIP信令处理分配 |
* @Description: SIP信令处理分配 |
||||
* @author: swwheihei |
* @author: swwheihei |
||||
* @date: 2020年5月3日 下午4:24:37 |
* @date: 2020年5月3日 下午4:24:37 |
||||
*/ |
*/ |
||||
@Component |
@Component |
||||
public class SIPProcessorFactory { |
public class SIPProcessorFactory { |
||||
|
|
||||
// private final static Logger logger = LoggerFactory.getLogger(SIPProcessorFactory.class);
|
// private final static Logger logger = LoggerFactory.getLogger(SIPProcessorFactory.class);
|
||||
|
|
||||
@Autowired |
@Autowired |
||||
private SipConfig sipConfig; |
private SipConfig sipConfig; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private RegisterLogicHandler handler; |
private RegisterLogicHandler handler; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private IVideoManagerStorager storager; |
private IVideoManagerStorager storager; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private IRedisCatchStorage redisCatchStorage; |
private IRedisCatchStorage redisCatchStorage; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private EventPublisher publisher; |
private EventPublisher publisher; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private SIPCommander cmder; |
private SIPCommander cmder; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private SIPCommanderFroPlatform cmderFroPlatform; |
private SIPCommanderFroPlatform cmderFroPlatform; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private RedisUtil redis; |
private RedisUtil redis; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private DeferredResultHolder deferredResultHolder; |
private DeferredResultHolder deferredResultHolder; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private DeviceOffLineDetector offLineDetector; |
private DeviceOffLineDetector offLineDetector; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private InviteResponseProcessor inviteResponseProcessor; |
private InviteResponseProcessor inviteResponseProcessor; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private ByeResponseProcessor byeResponseProcessor; |
private ByeResponseProcessor byeResponseProcessor; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private CancelResponseProcessor cancelResponseProcessor; |
private CancelResponseProcessor cancelResponseProcessor; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
@Lazy |
@Lazy |
||||
private RegisterResponseProcessor registerResponseProcessor; |
private RegisterResponseProcessor registerResponseProcessor; |
||||
|
|
||||
|
|
||||
@Autowired |
@Autowired |
||||
private OtherResponseProcessor otherResponseProcessor; |
private OtherResponseProcessor otherResponseProcessor; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private IPlayService playService; |
private IPlayService playService; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private ZLMRTPServerFactory zlmrtpServerFactory; |
private ZLMRTPServerFactory zlmrtpServerFactory; |
||||
|
|
||||
|
|
||||
// 注:这里使用注解会导致循环依赖注入,暂用springBean
|
// 注:这里使用注解会导致循环依赖注入,暂用springBean
|
||||
private SipProvider tcpSipProvider; |
private SipProvider tcpSipProvider; |
||||
|
|
||||
// 注:这里使用注解会导致循环依赖注入,暂用springBean
|
// 注:这里使用注解会导致循环依赖注入,暂用springBean
|
||||
private SipProvider udpSipProvider; |
private SipProvider udpSipProvider; |
||||
|
|
||||
public ISIPRequestProcessor createRequestProcessor(RequestEvent evt) { |
public ISIPRequestProcessor createRequestProcessor(RequestEvent evt) { |
||||
Request request = evt.getRequest(); |
Request request = evt.getRequest(); |
||||
String method = request.getMethod(); |
String method = request.getMethod(); |
||||
// logger.info("接收到消息:"+request.getMethod());
|
// logger.info("接收到消息:"+request.getMethod());
|
||||
// sipSubscribe.getSubscribe(evt.getServerTransaction().getBranchId()).response(evt);
|
// sipSubscribe.getSubscribe(evt.getServerTransaction().getBranchId()).response(evt);
|
||||
if (Request.INVITE.equals(method)) { |
if (Request.INVITE.equals(method)) { |
||||
InviteRequestProcessor processor = new InviteRequestProcessor(); |
InviteRequestProcessor processor = new InviteRequestProcessor(); |
||||
processor.setRequestEvent(evt); |
processor.setRequestEvent(evt); |
||||
processor.setTcpSipProvider(getTcpSipProvider()); |
processor.setTcpSipProvider(getTcpSipProvider()); |
||||
processor.setUdpSipProvider(getUdpSipProvider()); |
processor.setUdpSipProvider(getUdpSipProvider()); |
||||
|
|
||||
processor.setCmder(cmder); |
processor.setCmder(cmder); |
||||
processor.setCmderFroPlatform(cmderFroPlatform); |
processor.setCmderFroPlatform(cmderFroPlatform); |
||||
processor.setPlayService(playService); |
processor.setPlayService(playService); |
||||
processor.setStorager(storager); |
processor.setStorager(storager); |
||||
processor.setRedisCatchStorage(redisCatchStorage); |
processor.setRedisCatchStorage(redisCatchStorage); |
||||
processor.setZlmrtpServerFactory(zlmrtpServerFactory); |
processor.setZlmrtpServerFactory(zlmrtpServerFactory); |
||||
return processor; |
return processor; |
||||
} else if (Request.REGISTER.equals(method)) { |
} else if (Request.REGISTER.equals(method)) { |
||||
RegisterRequestProcessor processor = new RegisterRequestProcessor(); |
RegisterRequestProcessor processor = new RegisterRequestProcessor(); |
||||
processor.setRequestEvent(evt); |
processor.setRequestEvent(evt); |
||||
processor.setTcpSipProvider(getTcpSipProvider()); |
processor.setTcpSipProvider(getTcpSipProvider()); |
||||
processor.setUdpSipProvider(getUdpSipProvider()); |
processor.setUdpSipProvider(getUdpSipProvider()); |
||||
processor.setHandler(handler); |
processor.setHandler(handler); |
||||
processor.setPublisher(publisher); |
processor.setPublisher(publisher); |
||||
processor.setSipConfig(sipConfig); |
processor.setSipConfig(sipConfig); |
||||
processor.setVideoManagerStorager(storager); |
processor.setVideoManagerStorager(storager); |
||||
return processor; |
return processor; |
||||
} else if (Request.SUBSCRIBE.equals(method)) { |
} else if (Request.SUBSCRIBE.equals(method)) { |
||||
SubscribeRequestProcessor processor = new SubscribeRequestProcessor(); |
SubscribeRequestProcessor processor = new SubscribeRequestProcessor(); |
||||
processor.setRequestEvent(evt); |
processor.setRequestEvent(evt); |
||||
return processor; |
return processor; |
||||
} else if (Request.ACK.equals(method)) { |
} else if (Request.ACK.equals(method)) { |
||||
AckRequestProcessor processor = new AckRequestProcessor(); |
AckRequestProcessor processor = new AckRequestProcessor(); |
||||
processor.setRequestEvent(evt); |
processor.setRequestEvent(evt); |
||||
processor.setRedisCatchStorage(redisCatchStorage); |
processor.setRedisCatchStorage(redisCatchStorage); |
||||
processor.setZlmrtpServerFactory(zlmrtpServerFactory); |
processor.setZlmrtpServerFactory(zlmrtpServerFactory); |
||||
return processor; |
return processor; |
||||
} else if (Request.BYE.equals(method)) { |
} else if (Request.BYE.equals(method)) { |
||||
ByeRequestProcessor processor = new ByeRequestProcessor(); |
ByeRequestProcessor processor = new ByeRequestProcessor(); |
||||
processor.setRequestEvent(evt); |
processor.setRequestEvent(evt); |
||||
processor.setRedisCatchStorage(redisCatchStorage); |
processor.setRedisCatchStorage(redisCatchStorage); |
||||
processor.setZlmrtpServerFactory(zlmrtpServerFactory); |
processor.setZlmrtpServerFactory(zlmrtpServerFactory); |
||||
processor.setSIPCommander(cmder); |
processor.setSIPCommander(cmder); |
||||
return processor; |
return processor; |
||||
} else if (Request.CANCEL.equals(method)) { |
} else if (Request.CANCEL.equals(method)) { |
||||
CancelRequestProcessor processor = new CancelRequestProcessor(); |
CancelRequestProcessor processor = new CancelRequestProcessor(); |
||||
processor.setRequestEvent(evt); |
processor.setRequestEvent(evt); |
||||
return processor; |
return processor; |
||||
} else if (Request.MESSAGE.equals(method)) { |
} else if (Request.MESSAGE.equals(method)) { |
||||
MessageRequestProcessor processor = new MessageRequestProcessor(); |
MessageRequestProcessor processor = new MessageRequestProcessor(); |
||||
processor.setRequestEvent(evt); |
processor.setRequestEvent(evt); |
||||
processor.setTcpSipProvider(getTcpSipProvider()); |
processor.setTcpSipProvider(getTcpSipProvider()); |
||||
processor.setUdpSipProvider(getUdpSipProvider()); |
processor.setUdpSipProvider(getUdpSipProvider()); |
||||
processor.setPublisher(publisher); |
processor.setPublisher(publisher); |
||||
processor.setRedis(redis); |
processor.setRedis(redis); |
||||
processor.setDeferredResultHolder(deferredResultHolder); |
processor.setDeferredResultHolder(deferredResultHolder); |
||||
processor.setOffLineDetector(offLineDetector); |
processor.setOffLineDetector(offLineDetector); |
||||
processor.setCmder(cmder); |
processor.setCmder(cmder); |
||||
processor.setCmderFroPlatform(cmderFroPlatform); |
processor.setCmderFroPlatform(cmderFroPlatform); |
||||
processor.setStorager(storager); |
processor.setStorager(storager); |
||||
processor.setRedisCatchStorage(redisCatchStorage); |
processor.setRedisCatchStorage(redisCatchStorage); |
||||
return processor; |
return processor; |
||||
} else if (Request.NOTIFY.equalsIgnoreCase(method)) { |
} else if (Request.NOTIFY.equalsIgnoreCase(method)) { |
||||
NotifyRequestProcessor processor = new NotifyRequestProcessor(); |
NotifyRequestProcessor processor = new NotifyRequestProcessor(); |
||||
processor.setRequestEvent(evt); |
processor.setRequestEvent(evt); |
||||
processor.setTcpSipProvider(getTcpSipProvider()); |
processor.setTcpSipProvider(getTcpSipProvider()); |
||||
processor.setUdpSipProvider(getUdpSipProvider()); |
processor.setUdpSipProvider(getUdpSipProvider()); |
||||
processor.setPublisher(publisher); |
processor.setPublisher(publisher); |
||||
processor.setRedis(redis); |
processor.setRedis(redis); |
||||
processor.setDeferredResultHolder(deferredResultHolder); |
processor.setDeferredResultHolder(deferredResultHolder); |
||||
processor.setOffLineDetector(offLineDetector); |
processor.setOffLineDetector(offLineDetector); |
||||
processor.setCmder(cmder); |
processor.setCmder(cmder); |
||||
processor.setStorager(storager); |
processor.setStorager(storager); |
||||
processor.setRedisCatchStorage(redisCatchStorage); |
processor.setRedisCatchStorage(redisCatchStorage); |
||||
return processor; |
return processor; |
||||
} else { |
} else { |
||||
OtherRequestProcessor processor = new OtherRequestProcessor(); |
OtherRequestProcessor processor = new OtherRequestProcessor(); |
||||
processor.setRequestEvent(evt); |
processor.setRequestEvent(evt); |
||||
return processor; |
return processor; |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) { |
public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) { |
||||
|
|
||||
Response response = evt.getResponse(); |
Response response = evt.getResponse(); |
||||
CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME); |
CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME); |
||||
String method = cseqHeader.getMethod(); |
String method = cseqHeader.getMethod(); |
||||
if(Request.INVITE.equals(method)){ |
if(Request.INVITE.equals(method)){ |
||||
return inviteResponseProcessor; |
return inviteResponseProcessor; |
||||
} else if (Request.BYE.equals(method)) { |
} else if (Request.BYE.equals(method)) { |
||||
return byeResponseProcessor; |
return byeResponseProcessor; |
||||
} else if (Request.CANCEL.equals(method)) { |
} else if (Request.CANCEL.equals(method)) { |
||||
return cancelResponseProcessor; |
return cancelResponseProcessor; |
||||
}else if (Request.REGISTER.equals(method)) { |
}else if (Request.REGISTER.equals(method)) { |
||||
return registerResponseProcessor; |
return registerResponseProcessor; |
||||
} else { |
} else { |
||||
return otherResponseProcessor; |
return otherResponseProcessor; |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
private SipProvider getTcpSipProvider() { |
private SipProvider getTcpSipProvider() { |
||||
if (tcpSipProvider == null) { |
if (tcpSipProvider == null) { |
||||
tcpSipProvider = (SipProvider) SpringBeanFactory.getBean("tcpSipProvider"); |
tcpSipProvider = (SipProvider) SpringBeanFactory.getBean("tcpSipProvider"); |
||||
} |
} |
||||
return tcpSipProvider; |
return tcpSipProvider; |
||||
} |
} |
||||
|
|
||||
private SipProvider getUdpSipProvider() { |
private SipProvider getUdpSipProvider() { |
||||
if (udpSipProvider == null) { |
if (udpSipProvider == null) { |
||||
udpSipProvider = (SipProvider) SpringBeanFactory.getBean("udpSipProvider"); |
udpSipProvider = (SipProvider) SpringBeanFactory.getBean("udpSipProvider"); |
||||
} |
} |
||||
return udpSipProvider; |
return udpSipProvider; |
||||
} |
} |
||||
|
|
||||
} |
} |
||||
|
@ -1,63 +1,60 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.transmit.callback; |
package com.genersoft.iot.vmp.gb28181.transmit.callback; |
||||
|
|
||||
import java.util.Map; |
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
import java.util.concurrent.ConcurrentHashMap; |
||||
|
|
||||
import org.springframework.http.HttpStatus; |
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.ResponseEntity; |
import org.springframework.http.ResponseEntity; |
||||
import org.springframework.stereotype.Component; |
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 |
||||
*/ |
*/ |
||||
@SuppressWarnings(value = {"rawtypes", "unchecked"}) |
@Component |
||||
@Component |
public class DeferredResultHolder { |
||||
public class DeferredResultHolder { |
|
||||
|
public static final String CALLBACK_CMD_DEVICESTATUS = "CALLBACK_DEVICESTATUS"; |
||||
public static final String CALLBACK_CMD_DEVICESTATUS = "CALLBACK_DEVICESTATUS"; |
|
||||
|
public static final String CALLBACK_CMD_DEVICEINFO = "CALLBACK_DEVICEINFO"; |
||||
public static final String CALLBACK_CMD_DEVICEINFO = "CALLBACK_DEVICEINFO"; |
|
||||
|
public static final String CALLBACK_CMD_DEVICECONTROL = "CALLBACK_DEVICECONTROL"; |
||||
public static final String CALLBACK_CMD_DEVICECONTROL = "CALLBACK_DEVICECONTROL"; |
|
||||
|
public static final String CALLBACK_CMD_DEVICECONFIG = "CALLBACK_DEVICECONFIG"; |
||||
public static final String CALLBACK_CMD_DEVICECONFIG = "CALLBACK_DEVICECONFIG"; |
|
||||
|
public static final String CALLBACK_CMD_CONFIGDOWNLOAD = "CALLBACK_CONFIGDOWNLOAD"; |
||||
public static final String CALLBACK_CMD_CONFIGDOWNLOAD = "CALLBACK_CONFIGDOWNLOAD"; |
|
||||
|
public static final String CALLBACK_CMD_CATALOG = "CALLBACK_CATALOG"; |
||||
public static final String CALLBACK_CMD_CATALOG = "CALLBACK_CATALOG"; |
|
||||
|
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_STOP = "CALLBACK_STOP"; |
||||
public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; |
|
||||
|
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"; |
|
||||
|
public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM"; |
||||
public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM"; |
|
||||
|
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, DeferredResult> map = new ConcurrentHashMap<String, DeferredResult>(); |
|
||||
|
public void put(String key, DeferredResult result) { |
||||
public void put(String key, DeferredResult result) { |
map.put(key, result); |
||||
map.put(key, result); |
} |
||||
} |
|
||||
|
public void invokeResult(RequestMessage msg) { |
||||
public DeferredResult get(String key) { |
// DeferredResult result = map.get(msg.getId());
|
||||
return map.get(key); |
// 获取并移除
|
||||
} |
DeferredResult result = map.remove(msg.getId()); |
||||
|
if (result == null) { |
||||
public void invokeResult(RequestMessage msg) { |
return; |
||||
DeferredResult result = map.get(msg.getId()); |
} |
||||
if (result == null) { |
result.setResult(new ResponseEntity<>(msg.getData(),HttpStatus.OK)); |
||||
return; |
} |
||||
} |
} |
||||
result.setResult(new ResponseEntity<>(msg.getData(),HttpStatus.OK)); |
|
||||
} |
|
||||
} |
|
||||
|
@ -1,300 +1,301 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.transmit.cmd; |
package com.genersoft.iot.vmp.gb28181.transmit.cmd; |
||||
|
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
import com.genersoft.iot.vmp.common.StreamInfo; |
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
import com.genersoft.iot.vmp.gb28181.bean.Device; |
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
||||
|
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
||||
/** |
|
||||
* @Description:设备能力接口,用于定义设备的控制、查询能力 |
/** |
||||
* @author: swwheihei |
* @Description:设备能力接口,用于定义设备的控制、查询能力 |
||||
* @date: 2020年5月3日 下午9:16:34 |
* @author: swwheihei |
||||
*/ |
* @date: 2020年5月3日 下午9:16:34 |
||||
public interface ISIPCommander { |
*/ |
||||
|
public interface ISIPCommander { |
||||
/** |
|
||||
* 云台方向放控制,使用配置文件中的默认镜头移动速度 |
/** |
||||
* |
* 云台方向放控制,使用配置文件中的默认镜头移动速度 |
||||
* @param device 控制设备 |
* |
||||
* @param channelId 预览通道 |
* @param device 控制设备 |
||||
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 |
* @param channelId 预览通道 |
||||
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移 |
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 |
||||
* @param moveSpeed 镜头移动速度 |
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移 |
||||
*/ |
* @param moveSpeed 镜头移动速度 |
||||
boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown); |
*/ |
||||
|
boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown); |
||||
/** |
|
||||
* 云台方向放控制 |
/** |
||||
* |
* 云台方向放控制 |
||||
* @param device 控制设备 |
* |
||||
* @param channelId 预览通道 |
* @param device 控制设备 |
||||
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 |
* @param channelId 预览通道 |
||||
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移 |
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 |
||||
* @param moveSpeed 镜头移动速度 |
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移 |
||||
*/ |
* @param moveSpeed 镜头移动速度 |
||||
boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed); |
*/ |
||||
|
boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed); |
||||
/** |
|
||||
* 云台缩放控制,使用配置文件中的默认镜头缩放速度 |
/** |
||||
* |
* 云台缩放控制,使用配置文件中的默认镜头缩放速度 |
||||
* @param device 控制设备 |
* |
||||
* @param channelId 预览通道 |
* @param device 控制设备 |
||||
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 |
* @param channelId 预览通道 |
||||
*/ |
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 |
||||
boolean ptzZoomCmd(Device device,String channelId,int inOut); |
*/ |
||||
|
boolean ptzZoomCmd(Device device,String channelId,int inOut); |
||||
/** |
|
||||
* 云台缩放控制 |
/** |
||||
* |
* 云台缩放控制 |
||||
* @param device 控制设备 |
* |
||||
* @param channelId 预览通道 |
* @param device 控制设备 |
||||
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 |
* @param channelId 预览通道 |
||||
* @param zoomSpeed 镜头缩放速度 |
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 |
||||
*/ |
* @param zoomSpeed 镜头缩放速度 |
||||
boolean ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed); |
*/ |
||||
|
boolean ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed); |
||||
/** |
|
||||
* 云台控制,支持方向与缩放控制 |
/** |
||||
* |
* 云台控制,支持方向与缩放控制 |
||||
* @param device 控制设备 |
* |
||||
* @param channelId 预览通道 |
* @param device 控制设备 |
||||
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 |
* @param channelId 预览通道 |
||||
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移 |
* @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 |
||||
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 |
* @param upDown 镜头上移下移 0:停止 1:上移 2:下移 |
||||
* @param moveSpeed 镜头移动速度 |
* @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 |
||||
* @param zoomSpeed 镜头缩放速度 |
* @param moveSpeed 镜头移动速度 |
||||
*/ |
* @param zoomSpeed 镜头缩放速度 |
||||
boolean ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed); |
*/ |
||||
|
boolean ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed); |
||||
/** |
|
||||
* 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 |
/** |
||||
* |
* 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 |
||||
* @param device 控制设备 |
* |
||||
* @param channelId 预览通道 |
* @param device 控制设备 |
||||
* @param cmdCode 指令码 |
* @param channelId 预览通道 |
||||
* @param parameter1 数据1 |
* @param cmdCode 指令码 |
||||
* @param parameter2 数据2 |
* @param parameter1 数据1 |
||||
* @param combineCode2 组合码2 |
* @param parameter2 数据2 |
||||
*/ |
* @param combineCode2 组合码2 |
||||
boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2); |
*/ |
||||
|
boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2); |
||||
/** |
|
||||
* 前端控制指令(用于转发上级指令) |
/** |
||||
* @param device 控制设备 |
* 前端控制指令(用于转发上级指令) |
||||
* @param channelId 预览通道 |
* @param device 控制设备 |
||||
* @param cmdString 前端控制指令串 |
* @param channelId 预览通道 |
||||
*/ |
* @param cmdString 前端控制指令串 |
||||
boolean fronEndCmd(Device device, String channelId, String cmdString); |
*/ |
||||
|
boolean fronEndCmd(Device device, String channelId, String cmdString); |
||||
/** |
|
||||
* 请求预览视频流 |
/** |
||||
* |
* 请求预览视频流 |
||||
* @param device 视频设备 |
* |
||||
* @param channelId 预览通道 |
* @param device 视频设备 |
||||
*/ |
* @param channelId 预览通道 |
||||
void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent); |
*/ |
||||
|
void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 请求回放视频流 |
/** |
||||
* |
* 请求回放视频流 |
||||
* @param device 视频设备 |
* |
||||
* @param channelId 预览通道 |
* @param device 视频设备 |
||||
* @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss |
* @param channelId 预览通道 |
||||
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss |
* @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss |
||||
*/ |
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss |
||||
void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent); |
*/ |
||||
|
void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 视频流停止 |
/** |
||||
* |
* 视频流停止 |
||||
* @param ssrc ssrc |
* |
||||
*/ |
* @param streamInfo streamInfo |
||||
void streamByeCmd(String ssrc, SipSubscribe.Event okEvent); |
* @param okEvent okEvent |
||||
void streamByeCmd(String ssrc); |
*/ |
||||
|
void stopStreamByeCmd(StreamInfo streamInfo, SipSubscribe.Event okEvent); |
||||
/** |
|
||||
* 语音广播 |
/** |
||||
* |
* 语音广播 |
||||
* @param device 视频设备 |
* |
||||
* @param channelId 预览通道 |
* @param device 视频设备 |
||||
*/ |
* @param channelId 预览通道 |
||||
boolean audioBroadcastCmd(Device device,String channelId); |
*/ |
||||
|
boolean audioBroadcastCmd(Device device,String channelId); |
||||
/** |
|
||||
* 语音广播 |
/** |
||||
* |
* 语音广播 |
||||
* @param device 视频设备 |
* |
||||
*/ |
* @param device 视频设备 |
||||
void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent); |
*/ |
||||
boolean audioBroadcastCmd(Device device); |
void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent); |
||||
|
boolean audioBroadcastCmd(Device device); |
||||
/** |
|
||||
* 音视频录像控制 |
/** |
||||
* |
* 音视频录像控制 |
||||
* @param device 视频设备 |
* |
||||
* @param channelId 预览通道 |
* @param device 视频设备 |
||||
* @param recordCmdStr 录像命令:Record / StopRecord |
* @param channelId 预览通道 |
||||
*/ |
* @param recordCmdStr 录像命令:Record / StopRecord |
||||
boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent); |
*/ |
||||
|
boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 远程启动控制命令 |
/** |
||||
* |
* 远程启动控制命令 |
||||
* @param device 视频设备 |
* |
||||
*/ |
* @param device 视频设备 |
||||
boolean teleBootCmd(Device device); |
*/ |
||||
|
boolean teleBootCmd(Device device); |
||||
/** |
|
||||
* 报警布防/撤防命令 |
/** |
||||
* |
* 报警布防/撤防命令 |
||||
* @param device 视频设备 |
* |
||||
* @param setGuard true: SetGuard, false: ResetGuard |
* @param device 视频设备 |
||||
*/ |
* @param setGuard true: SetGuard, false: ResetGuard |
||||
boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent); |
*/ |
||||
|
boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 报警复位命令 |
/** |
||||
* |
* 报警复位命令 |
||||
* @param device 视频设备 |
* |
||||
* @param alarmMethod 报警方式(可选) |
* @param device 视频设备 |
||||
* @param alarmType 报警类型(可选) |
* @param alarmMethod 报警方式(可选) |
||||
*/ |
* @param alarmType 报警类型(可选) |
||||
boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent); |
*/ |
||||
|
boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 |
/** |
||||
* |
* 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 |
||||
* @param device 视频设备 |
* |
||||
* @param channelId 预览通道 |
* @param device 视频设备 |
||||
*/ |
* @param channelId 预览通道 |
||||
boolean iFrameCmd(Device device, String channelId); |
*/ |
||||
|
boolean iFrameCmd(Device device, String channelId); |
||||
/** |
|
||||
* 看守位控制命令 |
/** |
||||
* |
* 看守位控制命令 |
||||
* @param device 视频设备 |
* |
||||
* @param enabled 看守位使能:1 = 开启,0 = 关闭 |
* @param device 视频设备 |
||||
* @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) |
* @param enabled 看守位使能:1 = 开启,0 = 关闭 |
||||
* @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 |
* @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) |
||||
*/ |
* @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 |
||||
boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent); |
*/ |
||||
|
boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 设备配置命令 |
/** |
||||
* |
* 设备配置命令 |
||||
* @param device 视频设备 |
* |
||||
*/ |
* @param device 视频设备 |
||||
boolean deviceConfigCmd(Device device); |
*/ |
||||
|
boolean deviceConfigCmd(Device device); |
||||
/** |
|
||||
* 设备配置命令:basicParam |
/** |
||||
* |
* 设备配置命令:basicParam |
||||
* @param device 视频设备 |
* |
||||
* @param channelId 通道编码(可选) |
* @param device 视频设备 |
||||
* @param name 设备/通道名称(可选) |
* @param channelId 通道编码(可选) |
||||
* @param expiration 注册过期时间(可选) |
* @param name 设备/通道名称(可选) |
||||
* @param heartBeatInterval 心跳间隔时间(可选) |
* @param expiration 注册过期时间(可选) |
||||
* @param heartBeatCount 心跳超时次数(可选) |
* @param heartBeatInterval 心跳间隔时间(可选) |
||||
*/ |
* @param heartBeatCount 心跳超时次数(可选) |
||||
boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent); |
*/ |
||||
|
boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 查询设备状态 |
/** |
||||
* |
* 查询设备状态 |
||||
* @param device 视频设备 |
* |
||||
*/ |
* @param device 视频设备 |
||||
boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent); |
*/ |
||||
|
boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 查询设备信息 |
/** |
||||
* |
* 查询设备信息 |
||||
* @param device 视频设备 |
* |
||||
* @return |
* @param device 视频设备 |
||||
*/ |
* @return |
||||
boolean deviceInfoQuery(Device device); |
*/ |
||||
|
boolean deviceInfoQuery(Device device); |
||||
/** |
|
||||
* 查询目录列表 |
/** |
||||
* |
* 查询目录列表 |
||||
* @param device 视频设备 |
* |
||||
*/ |
* @param device 视频设备 |
||||
boolean catalogQuery(Device device, SipSubscribe.Event errorEvent); |
*/ |
||||
|
boolean catalogQuery(Device device, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 查询录像信息 |
/** |
||||
* |
* 查询录像信息 |
||||
* @param device 视频设备 |
* |
||||
* @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss |
* @param device 视频设备 |
||||
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss |
* @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss |
||||
*/ |
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss |
||||
boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime); |
*/ |
||||
|
boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime); |
||||
/** |
|
||||
* 查询报警信息 |
/** |
||||
* |
* 查询报警信息 |
||||
* @param device 视频设备 |
* |
||||
* @param startPriority 报警起始级别(可选) |
* @param device 视频设备 |
||||
* @param endPriority 报警终止级别(可选) |
* @param startPriority 报警起始级别(可选) |
||||
* @param alarmMethod 报警方式条件(可选) |
* @param endPriority 报警终止级别(可选) |
||||
* @param alarmType 报警类型 |
* @param alarmMethod 报警方式条件(可选) |
||||
* @param startTime 报警发生起始时间(可选) |
* @param alarmType 报警类型 |
||||
* @param endTime 报警发生终止时间(可选) |
* @param startTime 报警发生起始时间(可选) |
||||
* @return true = 命令发送成功 |
* @param endTime 报警发生终止时间(可选) |
||||
*/ |
* @return true = 命令发送成功 |
||||
boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, |
*/ |
||||
String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent); |
boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, |
||||
|
String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 查询设备配置 |
/** |
||||
* |
* 查询设备配置 |
||||
* @param device 视频设备 |
* |
||||
* @param channelId 通道编码(可选) |
* @param device 视频设备 |
||||
* @param configType 配置类型: |
* @param channelId 通道编码(可选) |
||||
*/ |
* @param configType 配置类型: |
||||
boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent); |
*/ |
||||
|
boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 查询设备预置位置 |
/** |
||||
* |
* 查询设备预置位置 |
||||
* @param device 视频设备 |
* |
||||
*/ |
* @param device 视频设备 |
||||
boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent); |
*/ |
||||
|
boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 查询移动设备位置数据 |
/** |
||||
* |
* 查询移动设备位置数据 |
||||
* @param device 视频设备 |
* |
||||
*/ |
* @param device 视频设备 |
||||
boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent); |
*/ |
||||
|
boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent); |
||||
/** |
|
||||
* 订阅、取消订阅移动位置 |
/** |
||||
* |
* 订阅、取消订阅移动位置 |
||||
* @param device 视频设备 |
* |
||||
* @param expires 订阅超时时间(值=0时为取消订阅) |
* @param device 视频设备 |
||||
* @param interval 上报时间间隔 |
* @param expires 订阅超时时间(值=0时为取消订阅) |
||||
* @return true = 命令发送成功 |
* @param interval 上报时间间隔 |
||||
*/ |
* @return true = 命令发送成功 |
||||
boolean mobilePositionSubscribe(Device device, int expires, int interval); |
*/ |
||||
|
boolean mobilePositionSubscribe(Device device, int expires, int interval); |
||||
/** |
|
||||
* 订阅、取消订阅报警信息 |
/** |
||||
* @param device 视频设备 |
* 订阅、取消订阅报警信息 |
||||
* @param expires 订阅过期时间(0 = 取消订阅) |
* @param device 视频设备 |
||||
* @param startPriority 报警起始级别(可选) |
* @param expires 订阅过期时间(0 = 取消订阅) |
||||
* @param endPriority 报警终止级别(可选) |
* @param startPriority 报警起始级别(可选) |
||||
* @param alarmMethods 报警方式条件(可选) |
* @param endPriority 报警终止级别(可选) |
||||
* @param alarmType 报警类型 |
* @param alarmMethods 报警方式条件(可选) |
||||
* @param startTime 报警发生起始时间(可选) |
* @param alarmType 报警类型 |
||||
* @param endTime 报警发生终止时间(可选) |
* @param startTime 报警发生起始时间(可选) |
||||
* @return true = 命令发送成功 |
* @param endTime 报警发生终止时间(可选) |
||||
*/ |
* @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); |
||||
|
|
||||
/** |
|
||||
* 释放rtpserver |
/** |
||||
* @param device |
* 释放rtpserver |
||||
* @param channelId |
* @param device |
||||
*/ |
* @param channelId |
||||
void closeRTPServer(Device device, String channelId); |
*/ |
||||
} |
void closeRTPServer(Device device, String channelId); |
||||
|
} |
||||
|
@ -1,183 +1,183 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.transmit.cmd; |
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.InvalidArgumentException; |
import javax.sip.InvalidArgumentException; |
||||
import javax.sip.PeerUnavailableException; |
import javax.sip.PeerUnavailableException; |
||||
import javax.sip.SipFactory; |
import javax.sip.SipFactory; |
||||
// import javax.sip.SipProvider;
|
// import javax.sip.SipProvider;
|
||||
import javax.sip.address.Address; |
import javax.sip.address.Address; |
||||
import javax.sip.address.SipURI; |
import javax.sip.address.SipURI; |
||||
import javax.sip.header.*; |
import javax.sip.header.*; |
||||
import javax.sip.message.Request; |
import javax.sip.message.Request; |
||||
|
|
||||
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.stereotype.Component; |
import org.springframework.stereotype.Component; |
||||
|
|
||||
import com.genersoft.iot.vmp.conf.SipConfig; |
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 |
||||
*/ |
*/ |
||||
@Component |
@Component |
||||
public class SIPRequestHeaderProvider { |
public class SIPRequestHeaderProvider { |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private SipConfig sipConfig; |
private SipConfig sipConfig; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private SipFactory sipFactory; |
private SipFactory sipFactory; |
||||
|
|
||||
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; |
||||
// sipuri
|
// sipuri
|
||||
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); |
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); |
||||
// via
|
// via
|
||||
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
||||
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), |
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), |
||||
device.getTransport(), viaTag); |
device.getTransport(), viaTag); |
||||
viaHeader.setRPort(); |
viaHeader.setRPort(); |
||||
viaHeaders.add(viaHeader); |
viaHeaders.add(viaHeader); |
||||
// from
|
// from
|
||||
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), |
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), |
||||
sipConfig.getSipIp() + ":" + sipConfig.getSipPort()); |
sipConfig.getSipIp() + ":" + sipConfig.getSipPort()); |
||||
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI); |
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI); |
||||
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); |
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); |
||||
// to
|
// to
|
||||
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain()); |
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain()); |
||||
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI); |
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI); |
||||
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag); |
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag); |
||||
|
|
||||
// Forwards
|
// Forwards
|
||||
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
||||
// ceq
|
// ceq
|
||||
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE); |
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE); |
||||
|
|
||||
request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, |
request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, |
||||
toHeader, viaHeaders, maxForwards); |
toHeader, viaHeaders, maxForwards); |
||||
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml"); |
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml"); |
||||
request.setContent(content, contentTypeHeader); |
request.setContent(content, contentTypeHeader); |
||||
return request; |
return request; |
||||
} |
} |
||||
|
|
||||
public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { |
public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { |
||||
Request request = null; |
Request request = null; |
||||
//请求行
|
//请求行
|
||||
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, 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(device.getIp(), device.getPort(), device.getTransport(), viaTag); |
||||
viaHeader.setRPort(); |
viaHeader.setRPort(); |
||||
viaHeaders.add(viaHeader); |
viaHeaders.add(viaHeader); |
||||
|
|
||||
//from
|
//from
|
||||
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain()); |
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain()); |
||||
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.getSipDomain()); |
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,sipConfig.getSipDomain()); |
||||
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); |
||||
|
|
||||
//Forwards
|
//Forwards
|
||||
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
||||
|
|
||||
//ceq
|
//ceq
|
||||
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE); |
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE); |
||||
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); |
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); |
||||
|
|
||||
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); |
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); |
||||
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
|
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
|
||||
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); |
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); |
||||
// Subject
|
// Subject
|
||||
SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getSipId(), 0)); |
SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getSipId(), 0)); |
||||
request.addHeader(subjectHeader); |
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; |
||||
} |
} |
||||
|
|
||||
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) throws ParseException, InvalidArgumentException, PeerUnavailableException { |
||||
Request request = null; |
Request request = null; |
||||
//请求行
|
//请求行
|
||||
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); |
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), 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(device.getIp(), device.getPort(), device.getTransport(), viaTag); |
||||
viaHeader.setRPort(); |
viaHeader.setRPort(); |
||||
viaHeaders.add(viaHeader); |
viaHeaders.add(viaHeader); |
||||
//from
|
//from
|
||||
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain()); |
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain()); |
||||
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.getSipDomain()); |
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,sipConfig.getSipDomain()); |
||||
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); |
||||
|
|
||||
//Forwards
|
//Forwards
|
||||
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
||||
|
|
||||
//ceq
|
//ceq
|
||||
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE); |
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE); |
||||
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); |
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); |
||||
|
|
||||
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); |
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); |
||||
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
|
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
|
||||
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); |
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); |
||||
|
|
||||
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; |
||||
} |
} |
||||
|
|
||||
public Request createSubscribeRequest(Device device, String content, String viaTag, String fromTag, String toTag, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { |
public Request createSubscribeRequest(Device device, String content, String viaTag, String fromTag, String toTag, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { |
||||
Request request = null; |
Request request = null; |
||||
// sipuri
|
// sipuri
|
||||
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); |
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); |
||||
// via
|
// via
|
||||
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
||||
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), |
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), |
||||
device.getTransport(), viaTag); |
device.getTransport(), viaTag); |
||||
viaHeader.setRPort(); |
viaHeader.setRPort(); |
||||
viaHeaders.add(viaHeader); |
viaHeaders.add(viaHeader); |
||||
// from
|
// from
|
||||
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), |
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), |
||||
sipConfig.getSipIp() + ":" + sipConfig.getSipPort()); |
sipConfig.getSipIp() + ":" + sipConfig.getSipPort()); |
||||
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI); |
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI); |
||||
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); |
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); |
||||
// to
|
// to
|
||||
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain()); |
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain()); |
||||
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI); |
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI); |
||||
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag); |
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag); |
||||
|
|
||||
// Forwards
|
// Forwards
|
||||
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
||||
// ceq
|
// ceq
|
||||
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.SUBSCRIBE); |
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.SUBSCRIBE); |
||||
|
|
||||
request = sipFactory.createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader, |
request = sipFactory.createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader, |
||||
toHeader, viaHeaders, maxForwards); |
toHeader, viaHeaders, maxForwards); |
||||
|
|
||||
|
|
||||
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); |
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); |
||||
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); |
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); |
||||
|
|
||||
// Expires
|
// Expires
|
||||
ExpiresHeader expireHeader = sipFactory.createHeaderFactory().createExpiresHeader(expires); |
ExpiresHeader expireHeader = sipFactory.createHeaderFactory().createExpiresHeader(expires); |
||||
request.addHeader(expireHeader); |
request.addHeader(expireHeader); |
||||
|
|
||||
// Event
|
// Event
|
||||
EventHeader eventHeader = sipFactory.createHeaderFactory().createEventHeader(event); |
EventHeader eventHeader = sipFactory.createHeaderFactory().createEventHeader(event); |
||||
request.addHeader(eventHeader); |
request.addHeader(eventHeader); |
||||
|
|
||||
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml"); |
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml"); |
||||
request.setContent(content, contentTypeHeader); |
request.setContent(content, contentTypeHeader); |
||||
return request; |
return request; |
||||
} |
} |
||||
} |
} |
||||
|
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -1,68 +1,62 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.transmit.response.impl; |
package com.genersoft.iot.vmp.gb28181.transmit.response.impl; |
||||
|
|
||||
import java.text.ParseException; |
import com.genersoft.iot.vmp.conf.SipConfig; |
||||
|
import com.genersoft.iot.vmp.gb28181.SipLayer; |
||||
import javax.sip.Dialog; |
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; |
||||
import javax.sip.InvalidArgumentException; |
import org.springframework.stereotype.Component; |
||||
import javax.sip.ResponseEvent; |
|
||||
import javax.sip.SipException; |
import javax.sip.Dialog; |
||||
import javax.sip.address.SipURI; |
import javax.sip.InvalidArgumentException; |
||||
import javax.sip.header.CSeqHeader; |
import javax.sip.ResponseEvent; |
||||
import javax.sip.header.ViaHeader; |
import javax.sip.SipException; |
||||
import javax.sip.message.Request; |
import javax.sip.address.SipURI; |
||||
import javax.sip.message.Response; |
import javax.sip.header.CSeqHeader; |
||||
|
import javax.sip.header.ViaHeader; |
||||
// import org.slf4j.Logger;
|
import javax.sip.message.Request; |
||||
// import org.slf4j.LoggerFactory;
|
import javax.sip.message.Response; |
||||
import org.springframework.stereotype.Component; |
import java.text.ParseException; |
||||
|
|
||||
import com.genersoft.iot.vmp.conf.SipConfig; |
|
||||
import com.genersoft.iot.vmp.gb28181.SipLayer; |
/** |
||||
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; |
* @Description:处理INVITE响应 |
||||
|
* @author: swwheihei |
||||
|
* @date: 2020年5月3日 下午4:43:52 |
||||
/** |
*/ |
||||
* @Description:处理INVITE响应 |
@Component |
||||
* @author: swwheihei |
public class InviteResponseProcessor implements ISIPResponseProcessor { |
||||
* @date: 2020年5月3日 下午4:43:52 |
|
||||
*/ |
/** |
||||
@Component |
* 处理invite响应 |
||||
public class InviteResponseProcessor implements ISIPResponseProcessor { |
* |
||||
|
* @param evt 响应消息 |
||||
// private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class);
|
* @throws ParseException |
||||
|
*/ |
||||
/** |
@Override |
||||
* 处理invite响应 |
public void process(ResponseEvent evt, SipLayer layer, SipConfig config) throws ParseException { |
||||
* |
try { |
||||
* @param evt 响应消息 |
Response response = evt.getResponse(); |
||||
* @throws ParseException |
int statusCode = response.getStatusCode(); |
||||
*/ |
// trying不会回复
|
||||
@Override |
if (statusCode == Response.TRYING) { |
||||
public void process(ResponseEvent evt, SipLayer layer, SipConfig config) throws ParseException { |
} |
||||
try { |
// 成功响应
|
||||
Response response = evt.getResponse(); |
// 下发ack
|
||||
int statusCode = response.getStatusCode(); |
if (statusCode == Response.OK) { |
||||
// trying不会回复
|
Dialog dialog = evt.getDialog(); |
||||
if (statusCode == Response.TRYING) { |
CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME); |
||||
} |
Request reqAck = dialog.createAck(cseq.getSeqNumber()); |
||||
// 成功响应
|
|
||||
// 下发ack
|
SipURI requestURI = (SipURI) reqAck.getRequestURI(); |
||||
if (statusCode == Response.OK) { |
ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME); |
||||
Dialog dialog = evt.getDialog(); |
requestURI.setHost(viaHeader.getHost()); |
||||
CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME); |
requestURI.setPort(viaHeader.getPort()); |
||||
Request reqAck = dialog.createAck(cseq.getSeqNumber()); |
reqAck.setRequestURI(requestURI); |
||||
|
|
||||
SipURI requestURI = (SipURI) reqAck.getRequestURI(); |
dialog.sendAck(reqAck); |
||||
ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME); |
} |
||||
requestURI.setHost(viaHeader.getHost()); |
} catch (InvalidArgumentException | SipException e) { |
||||
requestURI.setPort(viaHeader.getPort()); |
e.printStackTrace(); |
||||
reqAck.setRequestURI(requestURI); |
} |
||||
|
} |
||||
dialog.sendAck(reqAck); |
|
||||
} |
} |
||||
} catch (InvalidArgumentException | SipException e) { |
|
||||
e.printStackTrace(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
@ -1,362 +1,360 @@ |
|||||
package com.genersoft.iot.vmp.media.zlm; |
package com.genersoft.iot.vmp.media.zlm; |
||||
|
|
||||
import java.util.UUID; |
import com.alibaba.fastjson.JSON; |
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
import com.alibaba.fastjson.JSON; |
import com.genersoft.iot.vmp.common.StreamInfo; |
||||
import com.genersoft.iot.vmp.common.StreamInfo; |
import com.genersoft.iot.vmp.conf.MediaConfig; |
||||
import com.genersoft.iot.vmp.conf.MediaServerConfig; |
import com.genersoft.iot.vmp.conf.MediaServerConfig; |
||||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
import com.genersoft.iot.vmp.gb28181.bean.Device; |
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
||||
import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
||||
import org.slf4j.Logger; |
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
||||
import org.slf4j.LoggerFactory; |
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
||||
import org.springframework.beans.factory.annotation.Value; |
import org.slf4j.Logger; |
||||
import org.springframework.http.HttpStatus; |
import org.slf4j.LoggerFactory; |
||||
import org.springframework.http.ResponseEntity; |
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.util.StringUtils; |
import org.springframework.http.HttpStatus; |
||||
import org.springframework.web.bind.annotation.PostMapping; |
import org.springframework.http.ResponseEntity; |
||||
import org.springframework.web.bind.annotation.RequestBody; |
import org.springframework.web.bind.annotation.*; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
|
||||
import org.springframework.web.bind.annotation.ResponseBody; |
import javax.servlet.http.HttpServletRequest; |
||||
import org.springframework.web.bind.annotation.RestController; |
|
||||
|
/** |
||||
import com.alibaba.fastjson.JSONObject; |
* @Description:针对 ZLMediaServer的hook事件监听 |
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
* @author: swwheihei |
||||
|
* @date: 2020年5月8日 上午10:46:48 |
||||
import javax.servlet.http.HttpServletRequest; |
*/ |
||||
|
@RestController |
||||
/** |
@RequestMapping("/index/hook") |
||||
* @Description:针对 ZLMediaServer的hook事件监听 |
public class ZLMHttpHookListener { |
||||
* @author: swwheihei |
|
||||
* @date: 2020年5月8日 上午10:46:48 |
private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class); |
||||
*/ |
|
||||
@RestController |
|
||||
@RequestMapping("/index/hook") |
@Autowired |
||||
public class ZLMHttpHookListener { |
private SIPCommander cmder; |
||||
|
|
||||
private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class); |
@Autowired |
||||
|
private IPlayService playService; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private SIPCommander cmder; |
private IVideoManagerStorager storager; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private IPlayService playService; |
private IRedisCatchStorage redisCatchStorage; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private IVideoManagerStorager storager; |
private ZLMMediaListManager zlmMediaListManager; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private IRedisCatchStorage redisCatchStorage; |
private ZLMHttpHookSubscribe subscribe; |
||||
|
@Autowired |
||||
@Autowired |
private ZLMHttpHookSubscribe subscribe; |
||||
private ZLMMediaListManager zlmMediaListManager; |
|
||||
|
@Autowired |
||||
@Autowired |
MediaConfig mediaConfig; |
||||
private ZLMHttpHookSubscribe subscribe; |
|
||||
|
@Autowired |
||||
@Value("${media.autoApplyPlay}") |
private VideoStreamSessionManager streamSession; |
||||
private boolean autoApplyPlay; |
|
||||
|
/** |
||||
@Value("${media.ip}") |
* 流量统计事件,播放器或推流器断开时并且耗用流量超过特定阈值时会触发此事件,阈值通过配置文件general.flowThreshold配置;此事件对回复不敏感。 |
||||
private String mediaIp; |
* |
||||
|
*/ |
||||
@Value("${media.wanIp}") |
@ResponseBody |
||||
private String mediaWanIp; |
@PostMapping(value = "/on_flow_report", produces = "application/json;charset=UTF-8") |
||||
|
public ResponseEntity<String> onFlowReport(@RequestBody JSONObject json){ |
||||
@Value("${media.port}") |
|
||||
private int mediaPort; |
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("ZLM HOOK on_flow_report API调用,参数:" + json.toString()); |
||||
/** |
} |
||||
* 流量统计事件,播放器或推流器断开时并且耗用流量超过特定阈值时会触发此事件,阈值通过配置文件general.flowThreshold配置;此事件对回复不敏感。 |
JSONObject ret = new JSONObject(); |
||||
* |
ret.put("code", 0); |
||||
*/ |
ret.put("msg", "success"); |
||||
@ResponseBody |
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
||||
@PostMapping(value = "/on_flow_report", produces = "application/json;charset=UTF-8") |
} |
||||
public ResponseEntity<String> onFlowReport(@RequestBody JSONObject json){ |
|
||||
|
/** |
||||
if (logger.isDebugEnabled()) { |
* 访问http文件服务器上hls之外的文件时触发。 |
||||
logger.debug("ZLM HOOK on_flow_report API调用,参数:" + json.toString()); |
* |
||||
} |
*/ |
||||
JSONObject ret = new JSONObject(); |
@ResponseBody |
||||
ret.put("code", 0); |
@PostMapping(value = "/on_http_access", produces = "application/json;charset=UTF-8") |
||||
ret.put("msg", "success"); |
public ResponseEntity<String> onHttpAccess(@RequestBody JSONObject json){ |
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
|
||||
} |
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("ZLM HOOK on_http_access API 调用,参数:" + json.toString()); |
||||
/** |
} |
||||
* 访问http文件服务器上hls之外的文件时触发。 |
JSONObject ret = new JSONObject(); |
||||
* |
ret.put("code", 0); |
||||
*/ |
ret.put("err", ""); |
||||
@ResponseBody |
ret.put("path", ""); |
||||
@PostMapping(value = "/on_http_access", produces = "application/json;charset=UTF-8") |
ret.put("second", 600); |
||||
public ResponseEntity<String> onHttpAccess(@RequestBody JSONObject json){ |
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
||||
|
} |
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("ZLM HOOK on_http_access API 调用,参数:" + json.toString()); |
/** |
||||
} |
* 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。 |
||||
JSONObject ret = new JSONObject(); |
* |
||||
ret.put("code", 0); |
*/ |
||||
ret.put("err", ""); |
@ResponseBody |
||||
ret.put("path", ""); |
@PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8") |
||||
ret.put("second", 600); |
public ResponseEntity<String> onPlay(@RequestBody JSONObject json){ |
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
|
||||
} |
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("ZLM HOOK on_play API调用,参数:" + json.toString()); |
||||
/** |
} |
||||
* 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。 |
JSONObject ret = new JSONObject(); |
||||
* |
ret.put("code", 0); |
||||
*/ |
ret.put("msg", "success"); |
||||
@ResponseBody |
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
||||
@PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8") |
} |
||||
public ResponseEntity<String> onPlay(@RequestBody JSONObject json){ |
|
||||
|
/** |
||||
if (logger.isDebugEnabled()) { |
* rtsp/rtmp/rtp推流鉴权事件。 |
||||
logger.debug("ZLM HOOK on_play API调用,参数:" + json.toString()); |
* |
||||
} |
*/ |
||||
JSONObject ret = new JSONObject(); |
@ResponseBody |
||||
ret.put("code", 0); |
@PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8") |
||||
ret.put("msg", "success"); |
public ResponseEntity<String> onPublish(@RequestBody JSONObject json){ |
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
|
||||
} |
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("ZLM HOOK on_publish API调用,参数:" + json.toString()); |
||||
/** |
} |
||||
* rtsp/rtmp/rtp推流鉴权事件。 |
|
||||
* |
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); |
||||
*/ |
if (subscribe != null) { |
||||
@ResponseBody |
subscribe.response(json); |
||||
@PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8") |
} |
||||
public ResponseEntity<String> onPublish(@RequestBody JSONObject json){ |
|
||||
|
JSONObject ret = new JSONObject(); |
||||
if (logger.isDebugEnabled()) { |
ret.put("code", 0); |
||||
logger.debug("ZLM HOOK on_publish API调用,参数:" + json.toString()); |
ret.put("msg", "success"); |
||||
} |
ret.put("enableHls", true); |
||||
|
ret.put("enableMP4", false); |
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); |
ret.put("enableRtxp", true); |
||||
if (subscribe != null) subscribe.response(json); |
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
||||
|
} |
||||
JSONObject ret = new JSONObject(); |
|
||||
ret.put("code", 0); |
/** |
||||
ret.put("msg", "success"); |
* 录制mp4完成后通知事件;此事件对回复不敏感。 |
||||
ret.put("enableHls", true); |
* |
||||
ret.put("enableMP4", false); |
*/ |
||||
ret.put("enableRtxp", true); |
@ResponseBody |
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
@PostMapping(value = "/on_record_mp4", produces = "application/json;charset=UTF-8") |
||||
} |
public ResponseEntity<String> onRecordMp4(@RequestBody JSONObject json){ |
||||
|
|
||||
/** |
if (logger.isDebugEnabled()) { |
||||
* 录制mp4完成后通知事件;此事件对回复不敏感。 |
logger.debug("ZLM HOOK on_record_mp4 API调用,参数:" + json.toString()); |
||||
* |
} |
||||
*/ |
JSONObject ret = new JSONObject(); |
||||
@ResponseBody |
ret.put("code", 0); |
||||
@PostMapping(value = "/on_record_mp4", produces = "application/json;charset=UTF-8") |
ret.put("msg", "success"); |
||||
public ResponseEntity<String> onRecordMp4(@RequestBody JSONObject json){ |
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
||||
|
} |
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("ZLM HOOK on_record_mp4 API调用,参数:" + json.toString()); |
/** |
||||
} |
* rtsp专用的鉴权事件,先触发on_rtsp_realm事件然后才会触发on_rtsp_auth事件。 |
||||
JSONObject ret = new JSONObject(); |
* |
||||
ret.put("code", 0); |
*/ |
||||
ret.put("msg", "success"); |
@ResponseBody |
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
@PostMapping(value = "/on_rtsp_realm", produces = "application/json;charset=UTF-8") |
||||
} |
public ResponseEntity<String> onRtspRealm(@RequestBody JSONObject json){ |
||||
|
|
||||
/** |
if (logger.isDebugEnabled()) { |
||||
* rtsp专用的鉴权事件,先触发on_rtsp_realm事件然后才会触发on_rtsp_auth事件。 |
logger.debug("ZLM HOOK on_rtsp_realm API调用,参数:" + json.toString()); |
||||
* |
} |
||||
*/ |
JSONObject ret = new JSONObject(); |
||||
@ResponseBody |
ret.put("code", 0); |
||||
@PostMapping(value = "/on_rtsp_realm", produces = "application/json;charset=UTF-8") |
ret.put("realm", ""); |
||||
public ResponseEntity<String> onRtspRealm(@RequestBody JSONObject json){ |
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
||||
|
} |
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("ZLM HOOK on_rtsp_realm API调用,参数:" + json.toString()); |
|
||||
} |
/** |
||||
JSONObject ret = new JSONObject(); |
* 该rtsp流是否开启rtsp专用方式的鉴权事件,开启后才会触发on_rtsp_auth事件。需要指出的是rtsp也支持url参数鉴权,它支持两种方式鉴权。 |
||||
ret.put("code", 0); |
* |
||||
ret.put("realm", ""); |
*/ |
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
@ResponseBody |
||||
} |
@PostMapping(value = "/on_rtsp_auth", produces = "application/json;charset=UTF-8") |
||||
|
public ResponseEntity<String> onRtspAuth(@RequestBody JSONObject json){ |
||||
|
|
||||
/** |
if (logger.isDebugEnabled()) { |
||||
* 该rtsp流是否开启rtsp专用方式的鉴权事件,开启后才会触发on_rtsp_auth事件。需要指出的是rtsp也支持url参数鉴权,它支持两种方式鉴权。 |
logger.debug("ZLM HOOK on_rtsp_auth API调用,参数:" + json.toString()); |
||||
* |
} |
||||
*/ |
JSONObject ret = new JSONObject(); |
||||
@ResponseBody |
ret.put("code", 0); |
||||
@PostMapping(value = "/on_rtsp_auth", produces = "application/json;charset=UTF-8") |
ret.put("encrypted", false); |
||||
public ResponseEntity<String> onRtspAuth(@RequestBody JSONObject json){ |
ret.put("passwd", "test"); |
||||
|
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
||||
if (logger.isDebugEnabled()) { |
} |
||||
logger.debug("ZLM HOOK on_rtsp_auth API调用,参数:" + json.toString()); |
|
||||
} |
/** |
||||
JSONObject ret = new JSONObject(); |
* shell登录鉴权,ZLMediaKit提供简单的telnet调试方式,使用telnet 127.0.0.1 9000能进入MediaServer进程的shell界面。 |
||||
ret.put("code", 0); |
* |
||||
ret.put("encrypted", false); |
*/ |
||||
ret.put("passwd", "test"); |
@ResponseBody |
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
@PostMapping(value = "/on_shell_login", produces = "application/json;charset=UTF-8") |
||||
} |
public ResponseEntity<String> onShellLogin(@RequestBody JSONObject json){ |
||||
|
|
||||
/** |
if (logger.isDebugEnabled()) { |
||||
* shell登录鉴权,ZLMediaKit提供简单的telnet调试方式,使用telnet 127.0.0.1 9000能进入MediaServer进程的shell界面。 |
logger.debug("ZLM HOOK on_shell_login API调用,参数:" + json.toString()); |
||||
* |
} |
||||
*/ |
// TODO 如果是带有rtpstream则开启按需拉流
|
||||
@ResponseBody |
// String app = json.getString("app");
|
||||
@PostMapping(value = "/on_shell_login", produces = "application/json;charset=UTF-8") |
// String stream = json.getString("stream");
|
||||
public ResponseEntity<String> onShellLogin(@RequestBody JSONObject json){ |
|
||||
|
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); |
||||
if (logger.isDebugEnabled()) { |
if (subscribe != null) subscribe.response(json); |
||||
logger.debug("ZLM HOOK on_shell_login API调用,参数:" + json.toString()); |
|
||||
} |
JSONObject ret = new JSONObject(); |
||||
// TODO 如果是带有rtpstream则开启按需拉流
|
ret.put("code", 0); |
||||
// String app = json.getString("app");
|
ret.put("msg", "success"); |
||||
// String stream = json.getString("stream");
|
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
||||
|
} |
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); |
|
||||
if (subscribe != null) subscribe.response(json); |
/** |
||||
|
* rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。 |
||||
JSONObject ret = new JSONObject(); |
*/ |
||||
ret.put("code", 0); |
@ResponseBody |
||||
ret.put("msg", "success"); |
@PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") |
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
public ResponseEntity<String> onStreamChanged(@RequestBody JSONObject json) { |
||||
} |
|
||||
|
if (logger.isDebugEnabled()) { |
||||
/** |
logger.debug("ZLM HOOK on_stream_changed API调用,参数:" + json.toString()); |
||||
* rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。 |
} |
||||
* |
|
||||
*/ |
JSONObject ret = new JSONObject(); |
||||
@ResponseBody |
ret.put("code", 0); |
||||
@PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") |
ret.put("msg", "success"); |
||||
public ResponseEntity<String> onStreamChanged(@RequestBody JSONObject json){ |
|
||||
|
// 流消失移除redis play
|
||||
if (logger.isDebugEnabled()) { |
String app = json.getString("app"); |
||||
logger.debug("ZLM HOOK on_stream_changed API调用,参数:" + json.toString()); |
String streamId = json.getString("stream"); |
||||
} |
boolean regist = json.getBoolean("regist"); |
||||
// 流消失移除redis play
|
if (!"rtp".equals(app) || regist) { |
||||
String app = json.getString("app"); |
if (!"rtp".equals(app) && "rtsp".equals(schema)){ |
||||
String streamId = json.getString("stream"); |
zlmMediaListManager.updateMediaList(); |
||||
String schema = json.getString("schema"); |
} |
||||
boolean regist = json.getBoolean("regist"); |
return new ResponseEntity<>(ret.toString(), HttpStatus.OK); |
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); |
} |
||||
if ("rtp".equals(app) && !regist ) { |
|
||||
if (streamInfo!=null){ |
String[] s = streamId.split("_"); |
||||
redisCatchStorage.stopPlay(streamInfo); |
if (s.length != 4) { |
||||
storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
return new ResponseEntity<>(ret.toString(), HttpStatus.OK); |
||||
}else{ |
} |
||||
streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); |
String channelId = s[3]; |
||||
redisCatchStorage.stopPlayback(streamInfo); |
// TODO channelId
|
||||
} |
StreamInfo streamInfo = streamSession.getStreamInfo(channelId, streamId); |
||||
}else { |
if (null != streamInfo) { |
||||
if (!"rtp".equals(app) && "rtsp".equals(schema)){ |
cmder.stopStreamByeCmd(streamInfo, null); |
||||
zlmMediaListManager.updateMediaList(); |
} |
||||
} |
return new ResponseEntity<>(ret.toString(), HttpStatus.OK); |
||||
} |
} |
||||
JSONObject ret = new JSONObject(); |
|
||||
ret.put("code", 0); |
/** |
||||
ret.put("msg", "success"); |
* 流无人观看时事件,用户可以通过此事件选择是否关闭无人看的流。 |
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
*/ |
||||
} |
@ResponseBody |
||||
|
@PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") |
||||
/** |
public ResponseEntity<String> onStreamNoneReader(@RequestBody JSONObject json) { |
||||
* 流无人观看时事件,用户可以通过此事件选择是否关闭无人看的流。 |
|
||||
* |
if (logger.isDebugEnabled()) { |
||||
*/ |
logger.debug("ZLM HOOK on_stream_none_reader API调用,参数:" + json.toString()); |
||||
@ResponseBody |
} |
||||
@PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") |
|
||||
public ResponseEntity<String> onStreamNoneReader(@RequestBody JSONObject json){ |
JSONObject ret = new JSONObject(); |
||||
|
ret.put("code", 0); |
||||
if (logger.isDebugEnabled()) { |
ret.put("close", true); |
||||
logger.debug("ZLM HOOK on_stream_none_reader API调用,参数:" + json.toString()); |
|
||||
} |
String app = json.getString("app"); |
||||
|
String streamId = json.getString("stream"); |
||||
String streamId = json.getString("stream"); |
if (!"rtp".equals(app) || streamId.indexOf("gb_play") < 0) { |
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); |
return new ResponseEntity<>(ret.toString(), HttpStatus.OK); |
||||
|
} |
||||
JSONObject ret = new JSONObject(); |
String[] s = streamId.split("_"); |
||||
ret.put("code", 0); |
if (s.length != 4) { |
||||
ret.put("close", true); |
return new ResponseEntity<>(ret.toString(), HttpStatus.OK); |
||||
|
} |
||||
if (streamInfo != null) { |
String channelId = s[3]; |
||||
if (redisCatchStorage.isChannelSendingRTP(streamInfo.getChannelId())) { |
// TODO channelId
|
||||
ret.put("close", false); |
StreamInfo streamInfo = streamSession.getStreamInfo(channelId, streamId); |
||||
} else { |
if (null != streamInfo) { |
||||
cmder.streamByeCmd(streamId); |
if (redisCatchStorage.isChannelSendingRTP(streamInfo.getChannelId())) { |
||||
redisCatchStorage.stopPlay(streamInfo); |
ret.put("close", false); |
||||
storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
} else { |
||||
} |
cmder.stopStreamByeCmd(streamInfo, null); |
||||
}else{ |
} |
||||
cmder.streamByeCmd(streamId); |
} |
||||
streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); |
return new ResponseEntity<>(ret.toString(), HttpStatus.OK); |
||||
redisCatchStorage.stopPlayback(streamInfo); |
} |
||||
} |
|
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
/** |
||||
} |
* 流未找到事件,用户可以在此事件触发时,立即去拉流,这样可以实现按需拉流;此事件对回复不敏感。 |
||||
|
*/ |
||||
/** |
@ResponseBody |
||||
* 流未找到事件,用户可以在此事件触发时,立即去拉流,这样可以实现按需拉流;此事件对回复不敏感。 |
@PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8") |
||||
* |
public ResponseEntity<String> onStreamNotFound(@RequestBody JSONObject json) { |
||||
*/ |
|
||||
@ResponseBody |
if (logger.isDebugEnabled()) { |
||||
@PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8") |
logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString()); |
||||
public ResponseEntity<String> onStreamNotFound(@RequestBody JSONObject json){ |
} |
||||
|
|
||||
if (logger.isDebugEnabled()) { |
JSONObject ret = new JSONObject(); |
||||
logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString()); |
ret.put("code", 0); |
||||
} |
ret.put("msg", "success"); |
||||
if (autoApplyPlay) { |
if (!mediaConfig.getAutoApplyPlay()) { |
||||
String app = json.getString("app"); |
return new ResponseEntity<>(ret.toString(), HttpStatus.OK); |
||||
String streamId = json.getString("stream"); |
} |
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); |
String app = json.getString("app"); |
||||
if ("rtp".equals(app) && streamId.indexOf("gb_play") > -1 && streamInfo == null) { |
String streamId = json.getString("stream"); |
||||
String[] s = streamId.split("_"); |
|
||||
if (s.length == 4) { |
if (!"rtp".equals(app) || streamId.indexOf("gb_play") < 0) { |
||||
String deviceId = s[2]; |
return new ResponseEntity<>(ret.toString(), HttpStatus.OK); |
||||
String channelId = s[3]; |
} |
||||
Device device = storager.queryVideoDevice(deviceId); |
String[] s = streamId.split("_"); |
||||
if (device != null) { |
if (s.length != 4) { |
||||
UUID uuid = UUID.randomUUID(); |
return new ResponseEntity<>(ret.toString(), HttpStatus.OK); |
||||
cmder.playStreamCmd(device, channelId, (JSONObject response) -> { |
} |
||||
logger.info("收到订阅消息: " + response.toJSONString()); |
String deviceId = s[2]; |
||||
playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); |
String channelId = s[3]; |
||||
}, null); |
StreamInfo streamInfo = streamSession.getStreamInfo(channelId, streamId); |
||||
} |
|
||||
|
if (streamInfo != null) { |
||||
} |
return new ResponseEntity<>(ret.toString(), HttpStatus.OK); |
||||
|
} |
||||
} |
Device device = storager.queryVideoDevice(deviceId); |
||||
|
if (device != null) { |
||||
} |
RequestMessage msg = playService.createCallbackPlayMsg(); |
||||
|
cmder.playStreamCmd(device, channelId, (JSONObject response) -> { |
||||
JSONObject ret = new JSONObject(); |
logger.info("收到订阅消息: " + response.toJSONString()); |
||||
ret.put("code", 0); |
playService.onPublishHandlerForPlay(response, deviceId, channelId, msg); |
||||
ret.put("msg", "success"); |
}, null); |
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
} |
||||
} |
return new ResponseEntity<>(ret.toString(), HttpStatus.OK); |
||||
|
} |
||||
/** |
|
||||
* 服务器启动事件,可以用于监听服务器崩溃重启;此事件对回复不敏感。 |
/** |
||||
* |
* 服务器启动事件,可以用于监听服务器崩溃重启;此事件对回复不敏感。 |
||||
*/ |
* |
||||
@ResponseBody |
*/ |
||||
@PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8") |
@ResponseBody |
||||
public ResponseEntity<String> onServerStarted(HttpServletRequest request, @RequestBody JSONObject json){ |
@PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8") |
||||
|
public ResponseEntity<String> onServerStarted(HttpServletRequest request, @RequestBody JSONObject json){ |
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("ZLM HOOK on_server_started API调用,参数:" + json.toString()); |
if (logger.isDebugEnabled()) { |
||||
} |
logger.debug("ZLM HOOK on_server_started API调用,参数:" + json.toString()); |
||||
|
} |
||||
// String data = json.getString("data");
|
|
||||
// List<MediaServerConfig> mediaServerConfigs = JSON.parseArray(JSON.toJSONString(json), MediaServerConfig.class);
|
MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class); |
||||
// MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0);
|
redisCatchStorage.updateMediaInfo(mediaServerConfig); |
||||
MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class); |
// TODO Auto-generated method stub
|
||||
mediaServerConfig.setWanIp(StringUtils.isEmpty(mediaWanIp)? mediaIp: mediaWanIp); |
|
||||
mediaServerConfig.setLocalIP(mediaIp); |
JSONObject ret = new JSONObject(); |
||||
redisCatchStorage.updateMediaInfo(mediaServerConfig); |
ret.put("code", 0); |
||||
JSONObject ret = new JSONObject(); |
ret.put("msg", "success"); |
||||
ret.put("code", 0); |
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK); |
||||
ret.put("msg", "success"); |
} |
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); |
} |
||||
} |
|
||||
} |
|
||||
|
@ -1,264 +1,278 @@ |
|||||
package com.genersoft.iot.vmp.storager; |
package com.genersoft.iot.vmp.storager; |
||||
|
|
||||
import java.util.List; |
import com.genersoft.iot.vmp.gb28181.bean.Device; |
||||
|
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
||||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce; |
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
||||
import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce; |
import com.github.pagehelper.PageInfo; |
||||
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
|
||||
import com.github.pagehelper.PageInfo; |
import java.util.List; |
||||
|
|
||||
/** |
/** |
||||
* @Description:视频设备数据存储接口 |
* @Description:视频设备数据存储接口 |
||||
* @author: swwheihei |
* @author: swwheihei |
||||
* @date: 2020年5月6日 下午2:14:31 |
* @date: 2020年5月6日 下午2:14:31 |
||||
*/ |
*/ |
||||
@SuppressWarnings("rawtypes") |
public interface IVideoManagerStorager { |
||||
public interface IVideoManagerStorager { |
|
||||
|
/** |
||||
/** |
* 根据设备ID判断设备是否存在 |
||||
* 根据设备ID判断设备是否存在 |
* |
||||
* |
* @param deviceId 设备ID |
||||
* @param deviceId 设备ID |
* @return true:存在 false:不存在 |
||||
* @return true:存在 false:不存在 |
*/ |
||||
*/ |
public boolean exists(String deviceId); |
||||
public boolean exists(String deviceId); |
|
||||
|
/** |
||||
/** |
* 视频设备创建 |
||||
* 视频设备创建 |
* |
||||
* |
* @param device 设备对象 |
||||
* @param device 设备对象 |
* @return true:创建成功 false:创建失败 |
||||
* @return true:创建成功 false:创建失败 |
*/ |
||||
*/ |
public boolean create(Device device); |
||||
public boolean create(Device device); |
|
||||
|
/** |
||||
/** |
* 视频设备更新 |
||||
* 视频设备更新 |
* |
||||
* |
* @param device 设备对象 |
||||
* @param device 设备对象 |
* @return true:创建成功 false:创建失败 |
||||
* @return true:创建成功 false:创建失败 |
*/ |
||||
*/ |
public boolean updateDevice(Device device); |
||||
public boolean updateDevice(Device device); |
|
||||
|
/** |
||||
/** |
* 添加设备通道 |
||||
* 添加设备通道 |
* |
||||
* |
* @param deviceId 设备id |
||||
* @param deviceId 设备id |
* @param channel 通道 |
||||
* @param channel 通道 |
*/ |
||||
*/ |
public void updateChannel(String deviceId, DeviceChannel channel); |
||||
public void updateChannel(String deviceId, DeviceChannel channel); |
|
||||
|
/** |
||||
/** |
* 开始播放 |
||||
* 开始播放 |
* |
||||
* @param deviceId 设备id |
* @param deviceId 设备id |
||||
* @param channelId 通道ID |
* @param channelId 通道ID |
||||
* @param streamId 流地址 |
* @param streamId 流地址 |
||||
*/ |
*/ |
||||
public void startPlay(String deviceId, String channelId, String streamId); |
public void startPlay(String deviceId, String channelId, String streamId); |
||||
|
|
||||
/** |
/** |
||||
* 停止播放 |
* 停止播放 |
||||
* @param deviceId 设备id |
* |
||||
* @param channelId 通道ID |
* @param deviceId 设备id |
||||
*/ |
* @param channelId 通道ID |
||||
public void stopPlay(String deviceId, String channelId); |
*/ |
||||
|
public void stopPlay(String deviceId, String channelId); |
||||
/** |
|
||||
* 获取设备 |
/** |
||||
* |
* 获取设备 |
||||
* @param deviceId 设备ID |
* |
||||
* @return DShadow 设备对象 |
* @param deviceId 设备ID |
||||
*/ |
* @return DShadow 设备对象 |
||||
public Device queryVideoDevice(String deviceId); |
*/ |
||||
|
public Device queryVideoDevice(String deviceId); |
||||
/** |
|
||||
* 获取某个设备的通道列表 |
/** |
||||
* |
* 获取某个设备的通道列表 |
||||
* @param deviceId 设备ID |
* |
||||
* @param page 分页 当前页 |
* @param deviceId 设备ID |
||||
* @param count 每页数量 |
* @param page 分页 当前页 |
||||
* @return |
* @param count 每页数量 |
||||
*/ |
* @return |
||||
public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count); |
*/ |
||||
|
public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count); |
||||
/** |
|
||||
* 获取某个设备的通道列表 |
/** |
||||
* |
* 获取某个设备的通道列表 |
||||
* @param deviceId 设备ID |
* |
||||
* @return |
* @param deviceId 设备ID |
||||
*/ |
* @return |
||||
public List<DeviceChannel> queryChannelsByDeviceId(String deviceId); |
*/ |
||||
|
public List<DeviceChannel> queryChannelsByDeviceId(String deviceId); |
||||
/** |
|
||||
* 获取某个设备的通道 |
/** |
||||
* @param deviceId 设备ID |
* 获取某个设备的通道 |
||||
* @param channelId 通道ID |
* |
||||
*/ |
* @param deviceId 设备ID |
||||
public DeviceChannel queryChannel(String deviceId, String channelId); |
* @param channelId 通道ID |
||||
|
*/ |
||||
/** |
public DeviceChannel queryChannel(String deviceId, String channelId); |
||||
* 获取多个设备 |
|
||||
* @param page 当前页数 |
/** |
||||
* @param count 每页数量 |
* 获取多个设备 |
||||
* @return List<Device> 设备对象数组 |
* |
||||
*/ |
* @param page 当前页数 |
||||
public PageInfo<Device> queryVideoDeviceList(int page, int count); |
* @param count 每页数量 |
||||
|
* @return List<Device> 设备对象数组 |
||||
/** |
*/ |
||||
* 获取多个设备 |
public PageInfo<Device> queryVideoDeviceList(int page, int count); |
||||
* |
|
||||
* @return List<Device> 设备对象数组 |
/** |
||||
*/ |
* 获取多个设备 |
||||
public List<Device> queryVideoDeviceList(); |
* |
||||
|
* @return List<Device> 设备对象数组 |
||||
/** |
*/ |
||||
* 删除设备 |
public List<Device> queryVideoDeviceList(); |
||||
* |
|
||||
* @param deviceId 设备ID |
/** |
||||
* @return true:删除成功 false:删除失败 |
* 删除设备 |
||||
*/ |
* |
||||
public boolean delete(String deviceId); |
* @param deviceId 设备ID |
||||
|
* @return true:删除成功 false:删除失败 |
||||
/** |
*/ |
||||
* 更新设备在线 |
public boolean delete(String deviceId); |
||||
* |
|
||||
* @param deviceId 设备ID |
/** |
||||
* @return true:更新成功 false:更新失败 |
* 更新设备在线 |
||||
*/ |
* |
||||
public boolean online(String deviceId); |
* @param deviceId 设备ID |
||||
|
* @return true:更新成功 false:更新失败 |
||||
/** |
*/ |
||||
* 更新设备离线 |
public boolean online(String deviceId); |
||||
* |
|
||||
* @param deviceId 设备ID |
/** |
||||
* @return true:更新成功 false:更新失败 |
* 更新设备离线 |
||||
*/ |
* |
||||
public boolean outline(String deviceId); |
* @param deviceId 设备ID |
||||
|
* @return true:更新成功 false:更新失败 |
||||
|
*/ |
||||
/** |
public boolean outline(String deviceId); |
||||
* 查询子设备 |
|
||||
* |
|
||||
* @param deviceId |
/** |
||||
* @param channelId |
* 查询子设备 |
||||
* @param page |
* |
||||
* @param count |
* @param deviceId |
||||
* @return |
* @param channelId |
||||
*/ |
* @param page |
||||
PageInfo querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count); |
* @param count |
||||
|
* @return |
||||
|
*/ |
||||
/** |
PageInfo querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count); |
||||
* 清空通道 |
|
||||
* @param deviceId |
|
||||
*/ |
/** |
||||
void cleanChannelsForDevice(String deviceId); |
* 清空通道 |
||||
|
* |
||||
|
* @param deviceId |
||||
/** |
*/ |
||||
* 更新上级平台 |
void cleanChannelsForDevice(String deviceId); |
||||
* @param parentPlatform |
|
||||
*/ |
/** |
||||
boolean updateParentPlatform(ParentPlatform parentPlatform); |
* 添加Mobile Position设备移动位置 |
||||
|
* |
||||
|
* @param MobilePosition |
||||
/** |
* @return |
||||
* 添加上级平台 |
*/ |
||||
* @param parentPlatform |
public boolean insertMobilePosition(MobilePosition mobilePosition); |
||||
*/ |
|
||||
boolean addParentPlatform(ParentPlatform parentPlatform); |
/** |
||||
|
* 更新上级平台 |
||||
/** |
* @param parentPlatform |
||||
* 删除上级平台 |
*/ |
||||
* @param parentPlatform |
boolean updateParentPlatform(ParentPlatform parentPlatform); |
||||
*/ |
|
||||
boolean deleteParentPlatform(ParentPlatform parentPlatform); |
|
||||
|
/** |
||||
|
* 添加上级平台 |
||||
/** |
* @param parentPlatform |
||||
* 分页获取上级平台 |
*/ |
||||
* @param page |
boolean addParentPlatform(ParentPlatform parentPlatform); |
||||
* @param count |
|
||||
* @return |
/** |
||||
*/ |
* 删除上级平台 |
||||
PageInfo<ParentPlatform> queryParentPlatformList(int page, int count); |
* @param parentPlatform |
||||
|
*/ |
||||
/** |
boolean deleteParentPlatform(ParentPlatform parentPlatform); |
||||
* 获取所有已启用的平台 |
|
||||
* @return |
|
||||
*/ |
/** |
||||
List<ParentPlatform> queryEnableParentPlatformList(boolean enable); |
* 分页获取上级平台 |
||||
|
* @param page |
||||
/** |
* @param count |
||||
* 获取上级平台 |
* @return |
||||
* @param platformGbId |
*/ |
||||
* @return |
PageInfo<ParentPlatform> queryParentPlatformList(int page, int count); |
||||
*/ |
|
||||
ParentPlatform queryParentPlatById(String platformGbId); |
/** |
||||
|
* 获取所有已启用的平台 |
||||
/** |
* @return |
||||
* 所有平台离线 |
*/ |
||||
*/ |
List<ParentPlatform> queryEnableParentPlatformList(boolean enable); |
||||
void outlineForAllParentPlatform(); |
|
||||
|
/** |
||||
/** |
* 获取上级平台 |
||||
* 查询通道信息,不区分设备(已关联平台或全部) |
* @param platformGbId |
||||
*/ |
* @return |
||||
PageInfo<ChannelReduce> queryAllChannelList(int page, int count, String query, Boolean online, Boolean channelType, String platformId, Boolean inPlatform); |
*/ |
||||
|
ParentPlatform queryParentPlatById(String platformGbId); |
||||
/** |
|
||||
* 查询设备的通道信息 |
/** |
||||
*/ |
* 所有平台离线 |
||||
List<ChannelReduce> queryChannelListInParentPlatform(String platformId); |
*/ |
||||
|
void outlineForAllParentPlatform(); |
||||
|
|
||||
/** |
/** |
||||
* 更新上级平台的通道信息 |
* 查询通道信息,不区分设备(已关联平台或全部) |
||||
* @param platformId |
*/ |
||||
* @param channelReduces |
PageInfo<ChannelReduce> queryAllChannelList(int page, int count, String query, Boolean online, Boolean channelType, String platformId, Boolean inPlatform); |
||||
* @return |
|
||||
*/ |
/** |
||||
int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces); |
* 查询设备的通道信息 |
||||
|
*/ |
||||
/** |
List<ChannelReduce> queryChannelListInParentPlatform(String platformId); |
||||
* 移除上级平台的通道信息 |
|
||||
* @param platformId |
|
||||
* @param channelReduces |
/** |
||||
* @return |
* 更新上级平台的通道信息 |
||||
*/ |
* @param platformId |
||||
int delChannelForGB(String platformId, List<ChannelReduce> channelReduces); |
* @param channelReduces |
||||
|
* @return |
||||
|
*/ |
||||
DeviceChannel queryChannelInParentPlatform(String platformId, String channelId); |
int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces); |
||||
|
|
||||
Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); |
/** |
||||
|
* 移除上级平台的通道信息 |
||||
|
* @param platformId |
||||
/** |
* @param channelReduces |
||||
* 添加Mobile Position设备移动位置 |
* @return |
||||
* @param MobilePosition |
*/ |
||||
* @return |
int delChannelForGB(String platformId, List<ChannelReduce> channelReduces); |
||||
*/ |
|
||||
public boolean insertMobilePosition(MobilePosition mobilePosition); |
|
||||
|
DeviceChannel queryChannelInParentPlatform(String platformId, String channelId); |
||||
/** |
|
||||
* 查询移动位置轨迹 |
Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); |
||||
* @param deviceId |
|
||||
* @param startTime |
|
||||
* @param endTime |
/** |
||||
*/ |
* 添加Mobile Position设备移动位置 |
||||
public List<MobilePosition> queryMobilePositions(String deviceId, String startTime, String endTime); |
* @param MobilePosition |
||||
|
* @return |
||||
/** |
*/ |
||||
* 查询最新移动位置 |
public boolean insertMobilePosition(MobilePosition mobilePosition); |
||||
* @param deviceId |
|
||||
*/ |
/** |
||||
public MobilePosition queryLatestPosition(String deviceId); |
* 查询移动位置轨迹 |
||||
|
* |
||||
/** |
* @param deviceId |
||||
* 删除指定设备的所有移动位置 |
* @param startTime |
||||
* @param deviceId |
* @param endTime |
||||
*/ |
*/ |
||||
public int clearMobilePositionsByDeviceId(String deviceId); |
public List<MobilePosition> queryMobilePositions(String deviceId, String startTime, String endTime); |
||||
} |
|
||||
|
/** |
||||
|
* 查询最新移动位置 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
*/ |
||||
|
public MobilePosition queryLatestPosition(String deviceId); |
||||
|
|
||||
|
/** |
||||
|
* 删除指定设备的所有移动位置 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
*/ |
||||
|
public int clearMobilePositionsByDeviceId(String deviceId); |
||||
|
} |
||||
|
@ -0,0 +1,8 @@ |
|||||
|
package com.genersoft.iot.vmp.utils; |
||||
|
|
||||
|
public class ConfigConst { |
||||
|
/** |
||||
|
* 播流最大并发个数 |
||||
|
*/ |
||||
|
public static final Integer MAX_STRTEAM_COUNT = 10000; |
||||
|
} |
@ -0,0 +1,97 @@ |
|||||
|
package com.genersoft.iot.vmp.utils.redis; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import redis.clients.jedis.Jedis; |
||||
|
import redis.clients.jedis.JedisPool; |
||||
|
|
||||
|
import java.util.Set; |
||||
|
|
||||
|
/** |
||||
|
* @Description:Jedis工具类 |
||||
|
* @author: wangshaopeng@sunnybs.com |
||||
|
* @date: 2021年03月22日 下午8:27:29 |
||||
|
*/ |
||||
|
@Component |
||||
|
public class JedisUtil { |
||||
|
|
||||
|
@Autowired |
||||
|
private JedisPool jedisPool; |
||||
|
|
||||
|
// ============================== Key ==============================
|
||||
|
|
||||
|
/** |
||||
|
* 检查给定 key 是否存在。 |
||||
|
* |
||||
|
* @param key |
||||
|
* @return |
||||
|
*/ |
||||
|
public Boolean exists(String key) { |
||||
|
Jedis jedis = null; |
||||
|
try { |
||||
|
jedis = jedisPool.getResource(); |
||||
|
Boolean exists = jedis.exists(key); |
||||
|
return exists; |
||||
|
} finally { |
||||
|
returnToPool(jedis); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// ============================== Set ==============================
|
||||
|
|
||||
|
/** |
||||
|
* SADD key member [member ...] |
||||
|
* 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。 |
||||
|
* 假如 key 不存在,则创建一个只包含 member 元素作成员的集合。 |
||||
|
* 当 key 不是集合类型时,返回一个错误。 |
||||
|
*/ |
||||
|
public Long sadd(String key, String... members) { |
||||
|
Jedis jedis = null; |
||||
|
try { |
||||
|
jedis = jedisPool.getResource(); |
||||
|
Long smove = jedis.sadd(key, members); |
||||
|
return smove; |
||||
|
} finally { |
||||
|
returnToPool(jedis); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* SMEMBERS key |
||||
|
* 返回集合 key 中的所有成员。 |
||||
|
* 不存在的 key 被视为空集合。 |
||||
|
*/ |
||||
|
public Set<String> smembers(String key) { |
||||
|
Jedis jedis = null; |
||||
|
try { |
||||
|
jedis = jedisPool.getResource(); |
||||
|
Set<String> smembers = jedis.smembers(key); |
||||
|
return smembers; |
||||
|
} finally { |
||||
|
returnToPool(jedis); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* SREM key member1 [member2] |
||||
|
* 移除集合中一个或多个成员 |
||||
|
*/ |
||||
|
public Long srem(String key, String... member) { |
||||
|
Jedis jedis = null; |
||||
|
try { |
||||
|
jedis = jedisPool.getResource(); |
||||
|
Long srem = jedis.srem(key, member); |
||||
|
return srem; |
||||
|
} finally { |
||||
|
returnToPool(jedis); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void returnToPool(Jedis jedis) { |
||||
|
if (jedis != null) { |
||||
|
jedis.close(); |
||||
|
} |
||||
|
} |
||||
|
} |
File diff suppressed because it is too large
@ -1,120 +0,0 @@ |
|||||
/** |
|
||||
* 设备设置命令API接口 |
|
||||
* |
|
||||
* @author lawrencehj |
|
||||
* @date 2021年2月2日 |
|
||||
*/ |
|
||||
|
|
||||
package com.genersoft.iot.vmp.vmanager.device; |
|
||||
|
|
||||
import javax.sip.message.Response; |
|
||||
|
|
||||
import com.alibaba.fastjson.JSONObject; |
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|
||||
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.cmd.impl.SIPCommander; |
|
||||
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
|
||||
|
|
||||
import org.slf4j.Logger; |
|
||||
import org.slf4j.LoggerFactory; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.http.ResponseEntity; |
|
||||
import org.springframework.web.bind.annotation.*; |
|
||||
import org.springframework.web.context.request.async.DeferredResult; |
|
||||
|
|
||||
@CrossOrigin |
|
||||
@RestController |
|
||||
@RequestMapping("/api") |
|
||||
public class DeviceConfig { |
|
||||
|
|
||||
private final static Logger logger = LoggerFactory.getLogger(DeviceQuery.class); |
|
||||
|
|
||||
@Autowired |
|
||||
private IVideoManagerStorager storager; |
|
||||
|
|
||||
@Autowired |
|
||||
private SIPCommander cmder; |
|
||||
|
|
||||
@Autowired |
|
||||
private DeferredResultHolder resultHolder; |
|
||||
|
|
||||
/** |
|
||||
* 看守位控制命令API接口 |
|
||||
* |
|
||||
* @param deviceId |
|
||||
* @param enabled 看守位使能1:开启,0:关闭 |
|
||||
* @param resetTime 自动归位时间间隔(可选) |
|
||||
* @param presetIndex 调用预置位编号(可选) |
|
||||
* @param channelId 通道编码(可选) |
|
||||
*/ |
|
||||
@GetMapping("/config/{deviceId}/basicParam") |
|
||||
public DeferredResult<ResponseEntity<String>> homePositionApi(@PathVariable String deviceId, |
|
||||
@RequestParam(required = false) String channelId, |
|
||||
@RequestParam(required = false) String name, |
|
||||
@RequestParam(required = false) String expiration, |
|
||||
@RequestParam(required = false) String heartBeatInterval, |
|
||||
@RequestParam(required = false) String heartBeatCount) { |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("报警复位API调用"); |
|
||||
} |
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
cmder.deviceBasicConfigCmd(device, channelId, name, expiration, heartBeatInterval, heartBeatCount, event -> { |
|
||||
Response response = event.getResponse(); |
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|
||||
msg.setData(String.format("设备配置操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
|
||||
result.onTimeout(() -> { |
|
||||
logger.warn(String.format("设备配置操作超时, 设备未返回应答指令")); |
|
||||
// 释放rtpserver
|
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|
||||
JSONObject json = new JSONObject(); |
|
||||
json.put("DeviceID", deviceId); |
|
||||
json.put("Status", "Timeout"); |
|
||||
json.put("Description", "设备配置操作超时, 设备未返回应答指令"); |
|
||||
msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令");
|
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 设备配置查询请求API接口 |
|
||||
* |
|
||||
* @param deviceId |
|
||||
*/ |
|
||||
@GetMapping("/config/{deviceId}/query/{configType}") |
|
||||
public DeferredResult<ResponseEntity<String>> configDownloadApi(@PathVariable String deviceId, |
|
||||
@PathVariable String configType, |
|
||||
@RequestParam(required = false) String channelId) { |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("设备状态查询API调用"); |
|
||||
} |
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
cmder.deviceConfigQuery(device, channelId, configType, event -> { |
|
||||
Response response = event.getResponse(); |
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|
||||
msg.setData(String.format("获取设备配置失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String >> (3 * 1000L); |
|
||||
result.onTimeout(()->{ |
|
||||
logger.warn(String.format("获取设备配置超时")); |
|
||||
// 释放rtpserver
|
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|
||||
msg.setData("Timeout. Device did not response to this command."); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
} |
|
@ -0,0 +1,119 @@ |
|||||
|
/** |
||||
|
* 设备设置命令API接口 |
||||
|
* |
||||
|
* @author lawrencehj |
||||
|
* @date 2021年2月2日 |
||||
|
*/ |
||||
|
|
||||
|
package com.genersoft.iot.vmp.vmanager.device; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.genersoft.iot.vmp.gb28181.bean.Device; |
||||
|
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.cmd.impl.SIPCommander; |
||||
|
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
||||
|
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
import org.springframework.web.context.request.async.DeferredResult; |
||||
|
|
||||
|
import javax.sip.message.Response; |
||||
|
|
||||
|
@CrossOrigin |
||||
|
@RestController |
||||
|
@RequestMapping("/api") |
||||
|
public class DeviceConfigController { |
||||
|
|
||||
|
private final static Logger logger = LoggerFactory.getLogger(DeviceConfigController.class); |
||||
|
|
||||
|
@Autowired |
||||
|
private IVideoManagerStorager storager; |
||||
|
|
||||
|
@Autowired |
||||
|
private SIPCommander cmder; |
||||
|
|
||||
|
@Autowired |
||||
|
private DeferredResultHolder resultHolder; |
||||
|
|
||||
|
/** |
||||
|
* 看守位控制命令API接口 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
* @param enabled 看守位使能1:开启,0:关闭 |
||||
|
* @param resetTime 自动归位时间间隔(可选) |
||||
|
* @param presetIndex 调用预置位编号(可选) |
||||
|
* @param channelId 通道编码(可选) |
||||
|
*/ |
||||
|
@GetMapping("/config/{deviceId}/basicParam") |
||||
|
public DeferredResult<ResponseEntity<String>> homePositionApi(@PathVariable String deviceId, |
||||
|
@RequestParam(required = false) String channelId, |
||||
|
@RequestParam(required = false) String name, |
||||
|
@RequestParam(required = false) String expiration, |
||||
|
@RequestParam(required = false) String heartBeatInterval, |
||||
|
@RequestParam(required = false) String heartBeatCount) { |
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("报警复位API调用"); |
||||
|
} |
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
cmder.deviceBasicConfigCmd(device, channelId, name, expiration, heartBeatInterval, heartBeatCount, event -> { |
||||
|
Response response = event.getResponse(); |
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
||||
|
msg.setData(String.format("设备配置操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
||||
|
result.onTimeout(() -> { |
||||
|
logger.warn(String.format("设备配置操作超时, 设备未返回应答指令")); |
||||
|
// 释放rtpserver
|
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
||||
|
JSONObject json = new JSONObject(); |
||||
|
json.put("DeviceID", deviceId); |
||||
|
json.put("Status", "Timeout"); |
||||
|
json.put("Description", "设备配置操作超时, 设备未返回应答指令"); |
||||
|
msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令");
|
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设备配置查询请求API接口 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
*/ |
||||
|
@GetMapping("/config/{deviceId}/query/{configType}") |
||||
|
public DeferredResult<ResponseEntity<String>> configDownloadApi(@PathVariable String deviceId, |
||||
|
@PathVariable String configType, |
||||
|
@RequestParam(required = false) String channelId) { |
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("设备状态查询API调用"); |
||||
|
} |
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
cmder.deviceConfigQuery(device, channelId, configType, event -> { |
||||
|
Response response = event.getResponse(); |
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
||||
|
msg.setData(String.format("获取设备配置失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
||||
|
result.onTimeout(() -> { |
||||
|
logger.warn(String.format("获取设备配置超时")); |
||||
|
// 释放rtpserver
|
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
||||
|
msg.setData("Timeout. Device did not response to this command."); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
} |
@ -1,238 +0,0 @@ |
|||||
/** |
|
||||
* 设备控制命令API接口 |
|
||||
* |
|
||||
* @author lawrencehj |
|
||||
* @date 2021年2月1日 |
|
||||
*/ |
|
||||
|
|
||||
package com.genersoft.iot.vmp.vmanager.device; |
|
||||
|
|
||||
import javax.sip.message.Response; |
|
||||
|
|
||||
import com.alibaba.fastjson.JSONObject; |
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|
||||
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.cmd.impl.SIPCommander; |
|
||||
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
|
||||
|
|
||||
import org.slf4j.Logger; |
|
||||
import org.slf4j.LoggerFactory; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.http.HttpStatus; |
|
||||
import org.springframework.http.ResponseEntity; |
|
||||
import org.springframework.web.bind.annotation.*; |
|
||||
import org.springframework.web.context.request.async.DeferredResult; |
|
||||
|
|
||||
@CrossOrigin |
|
||||
@RestController |
|
||||
@RequestMapping("/api") |
|
||||
public class DeviceControl { |
|
||||
|
|
||||
private final static Logger logger = LoggerFactory.getLogger(DeviceQuery.class); |
|
||||
|
|
||||
@Autowired |
|
||||
private IVideoManagerStorager storager; |
|
||||
|
|
||||
@Autowired |
|
||||
private SIPCommander cmder; |
|
||||
|
|
||||
@Autowired |
|
||||
private DeferredResultHolder resultHolder; |
|
||||
|
|
||||
/** |
|
||||
* 远程启动控制命令API接口 |
|
||||
* |
|
||||
* @param deviceId |
|
||||
*/ |
|
||||
@GetMapping("/control/{deviceId}/teleboot") |
|
||||
@PostMapping("/control/{deviceId}/teleboot") |
|
||||
public ResponseEntity<String> teleBootApi(@PathVariable String deviceId) { |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("设备远程启动API调用"); |
|
||||
} |
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
boolean sucsess = cmder.teleBootCmd(device); |
|
||||
if (sucsess) { |
|
||||
JSONObject json = new JSONObject(); |
|
||||
json.put("DeviceID", deviceId); |
|
||||
json.put("Result", "OK"); |
|
||||
return new ResponseEntity<>(json.toJSONString(), HttpStatus.OK); |
|
||||
} else { |
|
||||
logger.warn("设备远程启动API调用失败!"); |
|
||||
return new ResponseEntity<String>("设备远程启动API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 录像控制命令API接口 |
|
||||
* |
|
||||
* @param deviceId |
|
||||
* @param recordCmdStr Record:手动录像,StopRecord:停止手动录像 |
|
||||
* @param channelId 通道编码(可选) |
|
||||
*/ |
|
||||
@GetMapping("/control/{deviceId}/record/{recordCmdStr}") |
|
||||
public DeferredResult<ResponseEntity<String>> recordApi(@PathVariable String deviceId, |
|
||||
@PathVariable String recordCmdStr, @RequestParam(required = false) String channelId) { |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("开始/停止录像API调用"); |
|
||||
} |
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
cmder.recordCmd(device, channelId, recordCmdStr, event -> { |
|
||||
Response response = event.getResponse(); |
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|
||||
msg.setData(String.format("开始/停止录像操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
|
||||
result.onTimeout(() -> { |
|
||||
logger.warn(String.format("开始/停止录像操作超时, 设备未返回应答指令")); |
|
||||
// 释放rtpserver
|
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|
||||
msg.setData("Timeout. Device did not response to this command."); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 报警布防/撤防命令API接口 |
|
||||
* |
|
||||
* @param deviceId |
|
||||
* @param guardCmdStr SetGuard:布防,ResetGuard:撤防 |
|
||||
*/ |
|
||||
@GetMapping("/control/{deviceId}/guard/{guardCmdStr}") |
|
||||
public DeferredResult<ResponseEntity<String>> guardApi(@PathVariable String deviceId, @PathVariable String guardCmdStr) { |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("布防/撤防API调用"); |
|
||||
} |
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
cmder.guardCmd(device, guardCmdStr, event -> { |
|
||||
Response response = event.getResponse(); |
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
|
||||
msg.setData(String.format("布防/撤防操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
|
||||
result.onTimeout(() -> { |
|
||||
logger.warn(String.format("布防/撤防操作超时, 设备未返回应答指令")); |
|
||||
// 释放rtpserver
|
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
|
||||
msg.setData("Timeout. Device did not response to this command."); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId, result); |
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 报警复位API接口 |
|
||||
* |
|
||||
* @param deviceId |
|
||||
* @param alarmMethod 报警方式(可选) |
|
||||
* @param alarmType 报警类型(可选) |
|
||||
*/ |
|
||||
@GetMapping("/control/{deviceId}/resetAlarm") |
|
||||
public DeferredResult<ResponseEntity<String>> resetAlarmApi(@PathVariable String deviceId, |
|
||||
@RequestParam(required = false) String alarmMethod, |
|
||||
@RequestParam(required = false) String alarmType) { |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("报警复位API调用"); |
|
||||
} |
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
cmder.alarmCmd(device, alarmMethod, alarmType, event -> { |
|
||||
Response response = event.getResponse(); |
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
|
||||
msg.setData(String.format("报警复位操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
|
||||
result.onTimeout(() -> { |
|
||||
logger.warn(String.format("报警复位操作超时, 设备未返回应答指令")); |
|
||||
// 释放rtpserver
|
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
|
||||
msg.setData("Timeout. Device did not response to this command."); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId, result); |
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 强制关键帧API接口 |
|
||||
* |
|
||||
* @param deviceId |
|
||||
* @param channelId |
|
||||
*/ |
|
||||
@GetMapping("/control/{deviceId}/iFrame") |
|
||||
@PostMapping("/control/{deviceId}/iFrame") |
|
||||
public ResponseEntity<String> iFrame(@PathVariable String deviceId, |
|
||||
@RequestParam(required = false) String channelId) { |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("强制关键帧API调用"); |
|
||||
} |
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
boolean sucsess = cmder.iFrameCmd(device, channelId); |
|
||||
if (sucsess) { |
|
||||
JSONObject json = new JSONObject(); |
|
||||
json.put("DeviceID", deviceId); |
|
||||
json.put("ChannelID", channelId); |
|
||||
json.put("Result", "OK"); |
|
||||
return new ResponseEntity<>(json.toJSONString(), HttpStatus.OK); |
|
||||
} else { |
|
||||
logger.warn("强制关键帧API调用失败!"); |
|
||||
return new ResponseEntity<String>("强制关键帧API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 看守位控制命令API接口 |
|
||||
* |
|
||||
* @param deviceId |
|
||||
* @param enabled 看守位使能1:开启,0:关闭 |
|
||||
* @param resetTime 自动归位时间间隔(可选) |
|
||||
* @param presetIndex 调用预置位编号(可选) |
|
||||
* @param channelId 通道编码(可选) |
|
||||
*/ |
|
||||
@GetMapping("/control/{deviceId}/homePosition/{enabled}") |
|
||||
public DeferredResult<ResponseEntity<String>> homePositionApi(@PathVariable String deviceId, |
|
||||
@PathVariable String enabled, |
|
||||
@RequestParam(required = false) String resetTime, |
|
||||
@RequestParam(required = false) String presetIndex, |
|
||||
@RequestParam(required = false) String channelId) { |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("报警复位API调用"); |
|
||||
} |
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> { |
|
||||
Response response = event.getResponse(); |
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|
||||
msg.setData(String.format("看守位控制操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
|
||||
result.onTimeout(() -> { |
|
||||
logger.warn(String.format("看守位控制操作超时, 设备未返回应答指令")); |
|
||||
// 释放rtpserver
|
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|
||||
JSONObject json = new JSONObject(); |
|
||||
json.put("DeviceID", deviceId); |
|
||||
json.put("Status", "Timeout"); |
|
||||
json.put("Description", "看守位控制操作超时, 设备未返回应答指令"); |
|
||||
msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令");
|
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
|
||||
return result; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,237 @@ |
|||||
|
/** |
||||
|
* 设备控制命令API接口 |
||||
|
* |
||||
|
* @author lawrencehj |
||||
|
* @date 2021年2月1日 |
||||
|
*/ |
||||
|
|
||||
|
package com.genersoft.iot.vmp.vmanager.device; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.genersoft.iot.vmp.gb28181.bean.Device; |
||||
|
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.cmd.impl.SIPCommander; |
||||
|
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
||||
|
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.http.HttpStatus; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
import org.springframework.web.context.request.async.DeferredResult; |
||||
|
|
||||
|
import javax.sip.message.Response; |
||||
|
|
||||
|
@CrossOrigin |
||||
|
@RestController |
||||
|
@RequestMapping("/api") |
||||
|
public class DeviceControlController { |
||||
|
|
||||
|
private final static Logger logger = LoggerFactory.getLogger(DeviceControlController.class); |
||||
|
|
||||
|
@Autowired |
||||
|
private IVideoManagerStorager storager; |
||||
|
|
||||
|
@Autowired |
||||
|
private SIPCommander cmder; |
||||
|
|
||||
|
@Autowired |
||||
|
private DeferredResultHolder resultHolder; |
||||
|
|
||||
|
/** |
||||
|
* 远程启动控制命令API接口 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
*/ |
||||
|
@GetMapping("/control/{deviceId}/teleboot") |
||||
|
@PostMapping("/control/{deviceId}/teleboot") |
||||
|
public ResponseEntity<String> teleBootApi(@PathVariable String deviceId) { |
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("设备远程启动API调用"); |
||||
|
} |
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
boolean sucsess = cmder.teleBootCmd(device); |
||||
|
if (sucsess) { |
||||
|
JSONObject json = new JSONObject(); |
||||
|
json.put("DeviceID", deviceId); |
||||
|
json.put("Result", "OK"); |
||||
|
return new ResponseEntity<>(json.toJSONString(), HttpStatus.OK); |
||||
|
} else { |
||||
|
logger.warn("设备远程启动API调用失败!"); |
||||
|
return new ResponseEntity<String>("设备远程启动API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 录像控制命令API接口 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
* @param recordCmdStr Record:手动录像,StopRecord:停止手动录像 |
||||
|
* @param channelId 通道编码(可选) |
||||
|
*/ |
||||
|
@GetMapping("/control/{deviceId}/record/{recordCmdStr}") |
||||
|
public DeferredResult<ResponseEntity<String>> recordApi(@PathVariable String deviceId, |
||||
|
@PathVariable String recordCmdStr, @RequestParam(required = false) String channelId) { |
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("开始/停止录像API调用"); |
||||
|
} |
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
cmder.recordCmd(device, channelId, recordCmdStr, event -> { |
||||
|
Response response = event.getResponse(); |
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
||||
|
msg.setData(String.format("开始/停止录像操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
||||
|
result.onTimeout(() -> { |
||||
|
logger.warn(String.format("开始/停止录像操作超时, 设备未返回应答指令")); |
||||
|
// 释放rtpserver
|
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
||||
|
msg.setData("Timeout. Device did not response to this command."); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 报警布防/撤防命令API接口 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
* @param guardCmdStr SetGuard:布防,ResetGuard:撤防 |
||||
|
*/ |
||||
|
@GetMapping("/control/{deviceId}/guard/{guardCmdStr}") |
||||
|
public DeferredResult<ResponseEntity<String>> guardApi(@PathVariable String deviceId, @PathVariable String guardCmdStr) { |
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("布防/撤防API调用"); |
||||
|
} |
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
cmder.guardCmd(device, guardCmdStr, event -> { |
||||
|
Response response = event.getResponse(); |
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
||||
|
msg.setData(String.format("布防/撤防操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
||||
|
result.onTimeout(() -> { |
||||
|
logger.warn(String.format("布防/撤防操作超时, 设备未返回应答指令")); |
||||
|
// 释放rtpserver
|
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
||||
|
msg.setData("Timeout. Device did not response to this command."); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId, result); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 报警复位API接口 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
* @param alarmMethod 报警方式(可选) |
||||
|
* @param alarmType 报警类型(可选) |
||||
|
*/ |
||||
|
@GetMapping("/control/{deviceId}/resetAlarm") |
||||
|
public DeferredResult<ResponseEntity<String>> resetAlarmApi(@PathVariable String deviceId, |
||||
|
@RequestParam(required = false) String alarmMethod, |
||||
|
@RequestParam(required = false) String alarmType) { |
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("报警复位API调用"); |
||||
|
} |
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
cmder.alarmCmd(device, alarmMethod, alarmType, event -> { |
||||
|
Response response = event.getResponse(); |
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
||||
|
msg.setData(String.format("报警复位操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
||||
|
result.onTimeout(() -> { |
||||
|
logger.warn(String.format("报警复位操作超时, 设备未返回应答指令")); |
||||
|
// 释放rtpserver
|
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
||||
|
msg.setData("Timeout. Device did not response to this command."); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId, result); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 强制关键帧API接口 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
* @param channelId |
||||
|
*/ |
||||
|
@GetMapping("/control/{deviceId}/iFrame") |
||||
|
@PostMapping("/control/{deviceId}/iFrame") |
||||
|
public ResponseEntity<String> iFrame(@PathVariable String deviceId, |
||||
|
@RequestParam(required = false) String channelId) { |
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("强制关键帧API调用"); |
||||
|
} |
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
boolean sucsess = cmder.iFrameCmd(device, channelId); |
||||
|
if (sucsess) { |
||||
|
JSONObject json = new JSONObject(); |
||||
|
json.put("DeviceID", deviceId); |
||||
|
json.put("ChannelID", channelId); |
||||
|
json.put("Result", "OK"); |
||||
|
return new ResponseEntity<>(json.toJSONString(), HttpStatus.OK); |
||||
|
} else { |
||||
|
logger.warn("强制关键帧API调用失败!"); |
||||
|
return new ResponseEntity<String>("强制关键帧API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 看守位控制命令API接口 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
* @param enabled 看守位使能1:开启,0:关闭 |
||||
|
* @param resetTime 自动归位时间间隔(可选) |
||||
|
* @param presetIndex 调用预置位编号(可选) |
||||
|
* @param channelId 通道编码(可选) |
||||
|
*/ |
||||
|
@GetMapping("/control/{deviceId}/homePosition/{enabled}") |
||||
|
public DeferredResult<ResponseEntity<String>> homePositionApi(@PathVariable String deviceId, |
||||
|
@PathVariable String enabled, |
||||
|
@RequestParam(required = false) String resetTime, |
||||
|
@RequestParam(required = false) String presetIndex, |
||||
|
@RequestParam(required = false) String channelId) { |
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("报警复位API调用"); |
||||
|
} |
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> { |
||||
|
Response response = event.getResponse(); |
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
||||
|
msg.setData(String.format("看守位控制操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
||||
|
result.onTimeout(() -> { |
||||
|
logger.warn(String.format("看守位控制操作超时, 设备未返回应答指令")); |
||||
|
// 释放rtpserver
|
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
||||
|
JSONObject json = new JSONObject(); |
||||
|
json.put("DeviceID", deviceId); |
||||
|
json.put("Status", "Timeout"); |
||||
|
json.put("Description", "看守位控制操作超时, 设备未返回应答指令"); |
||||
|
msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令");
|
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
||||
|
return result; |
||||
|
} |
||||
|
} |
@ -0,0 +1,261 @@ |
|||||
|
package com.genersoft.iot.vmp.vmanager.device; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.genersoft.iot.vmp.gb28181.bean.Device; |
||||
|
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
||||
|
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; |
||||
|
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.cmd.impl.SIPCommander; |
||||
|
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
||||
|
import com.github.pagehelper.PageInfo; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.http.HttpStatus; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
import org.springframework.web.context.request.async.DeferredResult; |
||||
|
|
||||
|
import javax.sip.message.Response; |
||||
|
|
||||
|
@CrossOrigin |
||||
|
@RestController |
||||
|
@RequestMapping("/api") |
||||
|
public class DeviceController { |
||||
|
|
||||
|
private final static Logger logger = LoggerFactory.getLogger(DeviceController.class); |
||||
|
|
||||
|
@Autowired |
||||
|
private IVideoManagerStorager storager; |
||||
|
|
||||
|
@Autowired |
||||
|
private SIPCommander cmder; |
||||
|
|
||||
|
@Autowired |
||||
|
private DeferredResultHolder resultHolder; |
||||
|
|
||||
|
@Autowired |
||||
|
private DeviceOffLineDetector offLineDetector; |
||||
|
|
||||
|
@GetMapping("/devices/{deviceId}") |
||||
|
public ResponseEntity<Device> devices(@PathVariable String deviceId) { |
||||
|
|
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("查询视频设备API调用,deviceId:" + deviceId); |
||||
|
} |
||||
|
|
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
return new ResponseEntity<>(device, HttpStatus.OK); |
||||
|
} |
||||
|
|
||||
|
@GetMapping("/devices") |
||||
|
public PageInfo<Device> devices(Integer page, Integer count) { |
||||
|
|
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("查询所有视频设备API调用"); |
||||
|
} |
||||
|
if (null == page) { |
||||
|
page = 1; |
||||
|
} |
||||
|
if (null == count) { |
||||
|
count = 10; |
||||
|
} |
||||
|
return storager.queryVideoDeviceList(page, count); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 分页查询通道数 |
||||
|
* |
||||
|
* @param deviceId 设备id |
||||
|
* @param page 当前页 |
||||
|
* @param count 每页条数 |
||||
|
* @param query 查询内容 |
||||
|
* @param online 是否在线 在线 true / 离线 false |
||||
|
* @param channelType 设备 false/子目录 true |
||||
|
* @return 通道列表 |
||||
|
*/ |
||||
|
@GetMapping("/devices/{deviceId}/channels") |
||||
|
public ResponseEntity<PageInfo> channels(@PathVariable String deviceId, |
||||
|
int page, int count, |
||||
|
@RequestParam(required = false) String query, |
||||
|
@RequestParam(required = false) Boolean online, |
||||
|
@RequestParam(required = false) Boolean channelType |
||||
|
) { |
||||
|
|
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("查询所有视频设备API调用"); |
||||
|
} |
||||
|
if (StringUtils.isEmpty(query)) { |
||||
|
query = null; |
||||
|
} |
||||
|
|
||||
|
PageInfo pageResult = storager.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count); |
||||
|
return new ResponseEntity<>(pageResult, HttpStatus.OK); |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/devices/{deviceId}/sync") |
||||
|
public DeferredResult<ResponseEntity<Device>> devicesSync(@PathVariable String deviceId) { |
||||
|
|
||||
|
if (logger.isDebugEnabled()) { |
||||
|
} |
||||
|
logger.debug("设备通道信息同步API调用,deviceId:" + deviceId); |
||||
|
|
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
cmder.catalogQuery(device, event -> { |
||||
|
Response response = event.getResponse(); |
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId); |
||||
|
msg.setData(String.format("同步通道失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(2 * 1000L); |
||||
|
result.onTimeout(() -> { |
||||
|
logger.warn(String.format("设备通道信息同步超时")); |
||||
|
// 释放rtpserver
|
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId); |
||||
|
msg.setData("Timeout"); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId, result); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/devices/{deviceId}/delete") |
||||
|
public ResponseEntity<String> delete(@PathVariable String deviceId) { |
||||
|
|
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("设备信息删除API调用,deviceId:" + deviceId); |
||||
|
} |
||||
|
|
||||
|
if (offLineDetector.isOnline(deviceId)) { |
||||
|
return new ResponseEntity<String>("不允许删除在线设备!", HttpStatus.NOT_ACCEPTABLE); |
||||
|
} |
||||
|
boolean isSuccess = storager.delete(deviceId); |
||||
|
if (isSuccess) { |
||||
|
JSONObject json = new JSONObject(); |
||||
|
json.put("deviceId", deviceId); |
||||
|
return new ResponseEntity<>(json.toString(), HttpStatus.OK); |
||||
|
} else { |
||||
|
logger.warn("设备信息删除API调用失败!"); |
||||
|
return new ResponseEntity<>("设备信息删除API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 分页查询通道数 |
||||
|
* |
||||
|
* @param channelId 通道id |
||||
|
* @param page 当前页 |
||||
|
* @param count 每页条数 |
||||
|
* @return 子通道列表 |
||||
|
*/ |
||||
|
@GetMapping("/subChannels/{deviceId}/{channelId}/channels") |
||||
|
public ResponseEntity<PageInfo> subChannels(@PathVariable String deviceId, |
||||
|
@PathVariable String channelId, |
||||
|
int page, |
||||
|
int count, |
||||
|
@RequestParam(required = false) String query, |
||||
|
@RequestParam(required = false) String online, |
||||
|
@RequestParam(required = false) Boolean channelType) { |
||||
|
|
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("查询所有视频通道API调用"); |
||||
|
} |
||||
|
DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); |
||||
|
if (deviceChannel == null) { |
||||
|
PageInfo<DeviceChannel> deviceChannelPageResult = new PageInfo<>(); |
||||
|
return new ResponseEntity<>(deviceChannelPageResult, HttpStatus.OK); |
||||
|
} |
||||
|
|
||||
|
PageInfo pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count); |
||||
|
return new ResponseEntity<>(pageResult, HttpStatus.OK); |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/channel/update/{deviceId}") |
||||
|
public ResponseEntity<PageInfo> updateChannel(@PathVariable String deviceId, DeviceChannel channel) { |
||||
|
storager.updateChannel(deviceId, channel); |
||||
|
return new ResponseEntity<>(null, HttpStatus.OK); |
||||
|
} |
||||
|
|
||||
|
@GetMapping("/devices/{deviceId}/transport/{streamMode}") |
||||
|
@PostMapping("/devices/{deviceId}/transport/{streamMode}") |
||||
|
public ResponseEntity<PageInfo> updateTransport(@PathVariable String deviceId, @PathVariable String streamMode) { |
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
device.setStreamMode(streamMode); |
||||
|
storager.updateDevice(device); |
||||
|
return new ResponseEntity<>(null, HttpStatus.OK); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设备状态查询请求API接口 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
*/ |
||||
|
@GetMapping("/devices/{deviceId}/status") |
||||
|
public DeferredResult<ResponseEntity<String>> deviceStatusApi(@PathVariable String deviceId) { |
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("设备状态查询API调用"); |
||||
|
} |
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
cmder.deviceStatusQuery(device, event -> { |
||||
|
Response response = event.getResponse(); |
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId); |
||||
|
msg.setData(String.format("获取设备状态失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(2 * 1000L); |
||||
|
result.onTimeout(() -> { |
||||
|
logger.warn(String.format("获取设备状态超时")); |
||||
|
// 释放rtpserver
|
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId); |
||||
|
msg.setData("Timeout. Device did not response to this command."); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId, result); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设备报警查询请求API接口 |
||||
|
* |
||||
|
* @param deviceId |
||||
|
*/ |
||||
|
@GetMapping("/alarm/{deviceId}") |
||||
|
public DeferredResult<ResponseEntity<String>> alarmApi(@PathVariable String deviceId, |
||||
|
@RequestParam(required = false) String startPriority, |
||||
|
@RequestParam(required = false) String endPriority, |
||||
|
@RequestParam(required = false) String alarmMethod, |
||||
|
@RequestParam(required = false) String alarmType, |
||||
|
@RequestParam(required = false) String startTime, |
||||
|
@RequestParam(required = false) String endTime) { |
||||
|
if (logger.isDebugEnabled()) { |
||||
|
logger.debug("设备报警查询API调用"); |
||||
|
} |
||||
|
Device device = storager.queryVideoDevice(deviceId); |
||||
|
cmder.alarmInfoQuery(device, startPriority, endPriority, alarmMethod, alarmType, startTime, endTime, event -> { |
||||
|
Response response = event.getResponse(); |
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId); |
||||
|
msg.setData(String.format("设备报警查询失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
||||
|
result.onTimeout(() -> { |
||||
|
logger.warn(String.format("设备报警查询超时")); |
||||
|
// 释放rtpserver
|
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId); |
||||
|
msg.setData("设备报警查询超时"); |
||||
|
resultHolder.invokeResult(msg); |
||||
|
}); |
||||
|
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId, result); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
@ -1,255 +0,0 @@ |
|||||
package com.genersoft.iot.vmp.vmanager.device; |
|
||||
|
|
||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
|
||||
import com.github.pagehelper.PageInfo; |
|
||||
import org.slf4j.Logger; |
|
||||
import org.slf4j.LoggerFactory; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.http.HttpStatus; |
|
||||
import org.springframework.http.ResponseEntity; |
|
||||
import org.springframework.util.StringUtils; |
|
||||
import org.springframework.web.bind.annotation.*; |
|
||||
import org.springframework.web.context.request.async.DeferredResult; |
|
||||
|
|
||||
import com.alibaba.fastjson.JSONObject; |
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|
||||
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; |
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
|
||||
|
|
||||
import javax.sip.message.Response; |
|
||||
|
|
||||
@SuppressWarnings("rawtypes") |
|
||||
@CrossOrigin |
|
||||
@RestController |
|
||||
@RequestMapping("/api") |
|
||||
public class DeviceQuery { |
|
||||
|
|
||||
private final static Logger logger = LoggerFactory.getLogger(DeviceQuery.class); |
|
||||
|
|
||||
@Autowired |
|
||||
private IVideoManagerStorager storager; |
|
||||
|
|
||||
@Autowired |
|
||||
private SIPCommander cmder; |
|
||||
|
|
||||
@Autowired |
|
||||
private DeferredResultHolder resultHolder; |
|
||||
|
|
||||
@Autowired |
|
||||
private DeviceOffLineDetector offLineDetector; |
|
||||
|
|
||||
@GetMapping("/devices/{deviceId}") |
|
||||
public ResponseEntity<Device> devices(@PathVariable String deviceId){ |
|
||||
|
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("查询视频设备API调用,deviceId:" + deviceId); |
|
||||
} |
|
||||
|
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
return new ResponseEntity<>(device,HttpStatus.OK); |
|
||||
} |
|
||||
|
|
||||
@GetMapping("/devices") |
|
||||
public PageInfo<Device> devices(int page, int count){ |
|
||||
|
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("查询所有视频设备API调用"); |
|
||||
} |
|
||||
|
|
||||
return storager.queryVideoDeviceList(page, count); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 分页查询通道数 |
|
||||
* |
|
||||
* @param deviceId 设备id |
|
||||
* @param page 当前页 |
|
||||
* @param count 每页条数 |
|
||||
* @param query 查询内容 |
|
||||
* @param online 是否在线 在线 true / 离线 false |
|
||||
* @param channelType 设备 false/子目录 true |
|
||||
* @return 通道列表 |
|
||||
*/ |
|
||||
@GetMapping("/devices/{deviceId}/channels") |
|
||||
public ResponseEntity<PageInfo> channels(@PathVariable String deviceId, |
|
||||
int page, int count, |
|
||||
@RequestParam(required = false) String query, |
|
||||
@RequestParam(required = false) Boolean online, |
|
||||
@RequestParam(required = false) Boolean channelType) { |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("查询视频设备通道API调用"); |
|
||||
} |
|
||||
if (StringUtils.isEmpty(query)) { |
|
||||
query = null; |
|
||||
} |
|
||||
|
|
||||
PageInfo pageResult = storager.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count); |
|
||||
return new ResponseEntity<>(pageResult,HttpStatus.OK); |
|
||||
} |
|
||||
|
|
||||
@PostMapping("/devices/{deviceId}/sync") |
|
||||
public DeferredResult<ResponseEntity<Device>> devicesSync(@PathVariable String deviceId){ |
|
||||
|
|
||||
if (logger.isDebugEnabled()) { |
|
||||
} |
|
||||
logger.debug("设备通道信息同步API调用,deviceId:" + deviceId); |
|
||||
|
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
cmder.catalogQuery(device, event -> { |
|
||||
Response response = event.getResponse(); |
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId); |
|
||||
msg.setData(String.format("同步通道失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(2*1000L); |
|
||||
result.onTimeout(()->{ |
|
||||
logger.warn(String.format("设备通道信息同步超时")); |
|
||||
// 释放rtpserver
|
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId); |
|
||||
msg.setData("Timeout"); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result); |
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
@PostMapping("/devices/{deviceId}/delete") |
|
||||
public ResponseEntity<String> delete(@PathVariable String deviceId){ |
|
||||
|
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("设备信息删除API调用,deviceId:" + deviceId); |
|
||||
} |
|
||||
|
|
||||
if (offLineDetector.isOnline(deviceId)) { |
|
||||
return new ResponseEntity<String>("不允许删除在线设备!", HttpStatus.NOT_ACCEPTABLE); |
|
||||
} |
|
||||
boolean isSuccess = storager.delete(deviceId); |
|
||||
if (isSuccess) { |
|
||||
JSONObject json = new JSONObject(); |
|
||||
json.put("deviceId", deviceId); |
|
||||
return new ResponseEntity<>(json.toString(),HttpStatus.OK); |
|
||||
} else { |
|
||||
logger.warn("设备信息删除API调用失败!"); |
|
||||
return new ResponseEntity<String>("设备信息删除API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 分页查询通道数 |
|
||||
* @param channelId 通道id |
|
||||
* @param page 当前页 |
|
||||
* @param count 每页条数 |
|
||||
* @return 子通道列表 |
|
||||
*/ |
|
||||
@GetMapping("/subChannels/{deviceId}/{channelId}/channels") |
|
||||
public ResponseEntity<PageInfo> subChannels(@PathVariable String deviceId, |
|
||||
@PathVariable String channelId, |
|
||||
int page, |
|
||||
int count, |
|
||||
@RequestParam(required = false) String query, |
|
||||
@RequestParam(required = false) String online, |
|
||||
@RequestParam(required = false) Boolean channelType){ |
|
||||
|
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("查询所有视频通道API调用"); |
|
||||
} |
|
||||
DeviceChannel deviceChannel = storager.queryChannel(deviceId,channelId); |
|
||||
if (deviceChannel == null) { |
|
||||
PageInfo<DeviceChannel> deviceChannelPageResult = new PageInfo<>(); |
|
||||
return new ResponseEntity<>(deviceChannelPageResult,HttpStatus.OK); |
|
||||
} |
|
||||
|
|
||||
PageInfo pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count); |
|
||||
return new ResponseEntity<>(pageResult,HttpStatus.OK); |
|
||||
} |
|
||||
|
|
||||
@PostMapping("/channel/update/{deviceId}") |
|
||||
public ResponseEntity<PageInfo> updateChannel(@PathVariable String deviceId,DeviceChannel channel){ |
|
||||
storager.updateChannel(deviceId, channel); |
|
||||
return new ResponseEntity<>(null,HttpStatus.OK); |
|
||||
} |
|
||||
|
|
||||
@GetMapping("/devices/{deviceId}/transport/{streamMode}") |
|
||||
@PostMapping("/devices/{deviceId}/transport/{streamMode}") |
|
||||
public ResponseEntity<PageInfo> updateTransport(@PathVariable String deviceId, @PathVariable String streamMode){ |
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
device.setStreamMode(streamMode); |
|
||||
storager.updateDevice(device); |
|
||||
return new ResponseEntity<>(null,HttpStatus.OK); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 设备状态查询请求API接口 |
|
||||
* |
|
||||
* @param deviceId |
|
||||
*/ |
|
||||
@GetMapping("/devices/{deviceId}/status") |
|
||||
public DeferredResult<ResponseEntity<String>> deviceStatusApi(@PathVariable String deviceId) { |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("设备状态查询API调用"); |
|
||||
} |
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
cmder.deviceStatusQuery(device, event -> { |
|
||||
Response response = event.getResponse(); |
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId); |
|
||||
msg.setData(String.format("获取设备状态失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(2*1000L); |
|
||||
result.onTimeout(()->{ |
|
||||
logger.warn(String.format("获取设备状态超时")); |
|
||||
// 释放rtpserver
|
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId); |
|
||||
msg.setData("Timeout. Device did not response to this command."); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId, result); |
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 设备报警查询请求API接口 |
|
||||
* |
|
||||
* @param deviceId |
|
||||
*/ |
|
||||
@GetMapping("/alarm/{deviceId}") |
|
||||
public DeferredResult<ResponseEntity<String>> alarmApi(@PathVariable String deviceId, |
|
||||
@RequestParam(required = false) String startPriority, |
|
||||
@RequestParam(required = false) String endPriority, |
|
||||
@RequestParam(required = false) String alarmMethod, |
|
||||
@RequestParam(required = false) String alarmType, |
|
||||
@RequestParam(required = false) String startTime, |
|
||||
@RequestParam(required = false) String endTime) { |
|
||||
if (logger.isDebugEnabled()) { |
|
||||
logger.debug("设备报警查询API调用"); |
|
||||
} |
|
||||
Device device = storager.queryVideoDevice(deviceId); |
|
||||
cmder.alarmInfoQuery(device, startPriority, endPriority, alarmMethod, alarmType, startTime, endTime, event -> { |
|
||||
Response response = event.getResponse(); |
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId); |
|
||||
msg.setData(String.format("设备报警查询失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String >> (3 * 1000L); |
|
||||
result.onTimeout(()->{ |
|
||||
logger.warn(String.format("设备报警查询超时")); |
|
||||
// 释放rtpserver
|
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId); |
|
||||
msg.setData("设备报警查询超时"); |
|
||||
resultHolder.invokeResult(msg); |
|
||||
}); |
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId, result); |
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
} |
|
@ -1,110 +1,101 @@ |
|||||
package com.genersoft.iot.vmp.vmanager.playback; |
package com.genersoft.iot.vmp.vmanager.playback; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
import com.genersoft.iot.vmp.common.StreamInfo; |
import com.genersoft.iot.vmp.common.StreamInfo; |
||||
|
import com.genersoft.iot.vmp.gb28181.bean.Device; |
||||
|
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
||||
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.callback.RequestMessage; |
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
||||
//import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
||||
import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
||||
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; |
||||
import org.springframework.http.HttpStatus; |
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.ResponseEntity; |
import org.springframework.http.ResponseEntity; |
||||
import org.springframework.web.bind.annotation.CrossOrigin; |
import org.springframework.web.bind.annotation.*; |
||||
import org.springframework.web.bind.annotation.GetMapping; |
|
||||
import org.springframework.web.bind.annotation.PathVariable; |
|
||||
import org.springframework.web.bind.annotation.RequestMapping; |
|
||||
import org.springframework.web.bind.annotation.RestController; |
|
||||
|
|
||||
import com.alibaba.fastjson.JSONObject; |
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
|
||||
import org.springframework.web.context.request.async.DeferredResult; |
import org.springframework.web.context.request.async.DeferredResult; |
||||
|
|
||||
import javax.sip.message.Response; |
import javax.sip.message.Response; |
||||
import java.util.UUID; |
|
||||
|
|
||||
@CrossOrigin |
@CrossOrigin |
||||
@RestController |
@RestController |
||||
@RequestMapping("/api") |
@RequestMapping("/api") |
||||
public class PlaybackController { |
public class PlaybackController { |
||||
|
|
||||
private final static Logger logger = LoggerFactory.getLogger(PlaybackController.class); |
private final static Logger logger = LoggerFactory.getLogger(PlaybackController.class); |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private SIPCommander cmder; |
private SIPCommander cmder; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private IVideoManagerStorager storager; |
private IVideoManagerStorager storager; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private IRedisCatchStorage redisCatchStorage; |
private VideoStreamSessionManager streamSession; |
||||
|
|
||||
// @Autowired
|
@Autowired |
||||
// private ZLMRESTfulUtils zlmresTfulUtils;
|
private IPlayService playService; |
||||
|
|
||||
@Autowired |
@Autowired |
||||
private IPlayService playService; |
private DeferredResultHolder resultHolder; |
||||
|
|
||||
@Autowired |
@GetMapping("/playback/{deviceId}/{channelId}") |
||||
private DeferredResultHolder resultHolder; |
public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId, @PathVariable String channelId, String startTime, |
||||
|
String endTime) { |
||||
@GetMapping("/playback/{deviceId}/{channelId}") |
|
||||
public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId, @PathVariable String channelId, String startTime, |
if (logger.isDebugEnabled()) { |
||||
String endTime) { |
logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); |
||||
|
} |
||||
if (logger.isDebugEnabled()) { |
RequestMessage msg = playService.createCallbackPlayMsg(); |
||||
logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); |
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(); |
||||
} |
// 超时处理
|
||||
UUID uuid = UUID.randomUUID(); |
result.onTimeout(() -> { |
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(); |
logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId)); |
||||
// 超时处理
|
StreamInfo streamInfo = streamSession.getPlayBackStreamInfo(channelId); |
||||
result.onTimeout(()->{ |
streamSession.remove(streamInfo); |
||||
logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId)); |
msg.setData("Timeout"); |
||||
RequestMessage msg = new RequestMessage(); |
resultHolder.invokeResult(msg); |
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); |
}); |
||||
msg.setData("Timeout"); |
Device device = storager.queryVideoDevice(deviceId); |
||||
resultHolder.invokeResult(msg); |
StreamInfo oldStreamInfo = streamSession.getPlayBackStreamInfo(channelId); |
||||
}); |
if (oldStreamInfo != null) { |
||||
Device device = storager.queryVideoDevice(deviceId); |
// TODO 只能停止自己之前的回放,不能停止别人的回放,否则会导致别人无法播放
|
||||
StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId); |
cmder.stopStreamByeCmd(oldStreamInfo, null); |
||||
if (streamInfo != null) { |
} |
||||
// 停止之前的回放
|
resultHolder.put(msg.getId(), result); |
||||
cmder.streamByeCmd(streamInfo.getStreamId()); |
cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> { |
||||
} |
logger.info("收到订阅消息: " + response.toJSONString()); |
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result); |
playService.onPublishHandlerForPlayBack(response, deviceId, channelId, msg); |
||||
cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> { |
}, event -> { |
||||
logger.info("收到订阅消息: " + response.toJSONString()); |
StreamInfo streamInfo = streamSession.getPlayBackStreamInfo(channelId); |
||||
playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString()); |
streamSession.remove(streamInfo); |
||||
}, event -> { |
Response response = event.getResponse(); |
||||
Response response = event.getResponse(); |
msg.setData(String.format("回放失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
||||
RequestMessage msg = new RequestMessage(); |
resultHolder.invokeResult(msg); |
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); |
}); |
||||
msg.setData(String.format("回放失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|
||||
resultHolder.invokeResult(msg); |
return result; |
||||
}); |
} |
||||
|
|
||||
return result; |
@RequestMapping("/playback/{channelId}/{ssrc}/stop") |
||||
} |
public ResponseEntity<String> playStop(@PathVariable String channelId, @PathVariable String ssrc) { |
||||
|
if (logger.isDebugEnabled()) { |
||||
@RequestMapping("/playback/{ssrc}/stop") |
logger.debug(String.format("设备录像回放停止 API调用,ssrc:%s", ssrc)); |
||||
public ResponseEntity<String> playStop(@PathVariable String ssrc) { |
} |
||||
|
if (ssrc == null) { |
||||
cmder.streamByeCmd(ssrc); |
logger.warn("设备录像回放停止API调用失败!"); |
||||
|
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); |
||||
if (logger.isDebugEnabled()) { |
} |
||||
logger.debug(String.format("设备录像回放停止 API调用,ssrc:%s", ssrc)); |
StreamInfo streamInfo = streamSession.getStreamInfo(channelId, ssrc); |
||||
} |
if (streamInfo == null) { |
||||
|
logger.warn("回放播流不存在!"); |
||||
if (ssrc != null) { |
return new ResponseEntity<>(HttpStatus.NOT_FOUND); |
||||
JSONObject json = new JSONObject(); |
} |
||||
json.put("ssrc", ssrc); |
cmder.stopStreamByeCmd(streamInfo, null); |
||||
return new ResponseEntity<String>(json.toString(), HttpStatus.OK); |
JSONObject json = new JSONObject(); |
||||
} else { |
json.put("ssrc", ssrc); |
||||
logger.warn("设备录像回放停止API调用失败!"); |
return new ResponseEntity<>(json.toString(), HttpStatus.OK); |
||||
return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR); |
} |
||||
} |
|
||||
} |
|
||||
} |
} |
||||
|
Loading…
Reference in new issue