优化集群方案, 每个zlm一套ssrc;
优化集群下的docker接入逻辑; 更正sql脚本; 支持重启不设置设备离线。重启SIP事务不丢失
This commit is contained in:
parent
379830f7eb
commit
3469271ec2
7
pom.xml
7
pom.xml
@ -46,6 +46,7 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.build.timestamp.format>MMddHHmm</maven.build.timestamp.format>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<jedis-version>3.1.0</jedis-version>
|
||||
|
||||
<!-- 依赖版本 -->
|
||||
<pagehelper.version>5.2.0</pagehelper.version>
|
||||
@ -80,6 +81,12 @@
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>${jedis-version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- druid数据库连接池 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
|
@ -1,5 +1,9 @@
|
||||
-- auto-generated definition
|
||||
create schema wvp collate utf8_bin;
|
||||
|
||||
|
||||
CREATE DATABASE `wvp` /*!40100 DEFAULT CHARACTER SET utf8mb3 COLLATE utf8mb3_bin */;
|
||||
|
||||
use wvp;
|
||||
|
||||
create table device
|
||||
(
|
||||
@ -50,7 +54,7 @@ create table device_channel
|
||||
streamId varchar(50) null,
|
||||
deviceId varchar(50) not null,
|
||||
parental varchar(50) null,
|
||||
hasAudio bit(1) null,
|
||||
hasAudio bit null,
|
||||
createTime varchar(50) not null,
|
||||
updateTime varchar(50) not null,
|
||||
primary key (channelId, deviceId)
|
||||
@ -82,10 +86,39 @@ create table gb_stream
|
||||
longitude double null,
|
||||
latitude double null,
|
||||
streamType varchar(50) null,
|
||||
mediaServerId varchar(50) null,
|
||||
status int null,
|
||||
primary key (app, stream, gbId)
|
||||
);
|
||||
|
||||
create table media_server
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
ip varchar(50) not null,
|
||||
hookIp varchar(50) not null,
|
||||
sdpIp varchar(50) not null,
|
||||
streamIp varchar(50) not null,
|
||||
httpPort int not null,
|
||||
httpSSlPort int not null,
|
||||
rtmpPort int not null,
|
||||
rtmpSSlPort int not null,
|
||||
rtpProxyPort int not null,
|
||||
rtspPort int not null,
|
||||
rtspSSLPort int not null,
|
||||
autoConfig int not null,
|
||||
secret varchar(50) not null,
|
||||
streamNoneReaderDelayMS int not null,
|
||||
rtpEnable int not null,
|
||||
rtpPortRange varchar(50) not null,
|
||||
recordAssistPort int not null,
|
||||
defaultServer int not null,
|
||||
createTime varchar(50) not null,
|
||||
updateTime varchar(50) not null,
|
||||
constraint media_server_i
|
||||
unique (ip, httpPort)
|
||||
);
|
||||
|
||||
create table parent_platform
|
||||
(
|
||||
id int auto_increment,
|
||||
@ -106,7 +139,7 @@ create table parent_platform
|
||||
characterSet varchar(50) null,
|
||||
ptz int null,
|
||||
rtcp int null,
|
||||
status bit(1) null,
|
||||
status bit null,
|
||||
primary key (id, serverGBId)
|
||||
);
|
||||
|
||||
@ -139,9 +172,10 @@ create table stream_proxy
|
||||
ffmpeg_cmd_key varchar(255) null,
|
||||
rtp_type varchar(50) null,
|
||||
mediaServerId varchar(50) null,
|
||||
enable_hls bit(1) null,
|
||||
enable_mp4 bit(1) null,
|
||||
enable bit(1) not null,
|
||||
enable_hls bit null,
|
||||
enable_mp4 bit null,
|
||||
enable bit not null,
|
||||
createTime varchar(50) not null,
|
||||
primary key (app, stream)
|
||||
);
|
||||
|
||||
@ -154,6 +188,7 @@ create table stream_push
|
||||
originTypeStr varchar(50) null,
|
||||
createStamp int null,
|
||||
aliveSecond int null,
|
||||
mediaServerId varchar(50) null,
|
||||
primary key (app, stream)
|
||||
);
|
||||
|
||||
@ -167,28 +202,3 @@ create table user
|
||||
create_time varchar(50) not null
|
||||
);
|
||||
|
||||
insert into user (username, password, roleId, create_time) values ('admin', '21232f297a57a5a743894a0e4a801fc3', '0', '2021-04-13 14:14:57');
|
||||
|
||||
create table media_server (
|
||||
id varchar(255)
|
||||
primary key,
|
||||
ip varchar(50) NOT NULL,
|
||||
hookIp varchar(50) NOT NULL,
|
||||
sdpIp varchar(50) NOT NULL,
|
||||
streamIp varchar(50) NOT NULL,
|
||||
httpPort int NOT NULL,
|
||||
httpSSlPort int NOT NULL,
|
||||
rtmpPort int NOT NULL,
|
||||
rtmpSSlPort int NOT NULL,
|
||||
rtpProxyPort int NOT NULL,
|
||||
rtspPort int NOT NULL,
|
||||
rtspSSLPort int NOT NULL,
|
||||
autoConfig int NOT NULL,
|
||||
secret varchar(50) NOT NULL,
|
||||
streamNoneReaderDelayMS int NOT NULL,
|
||||
rtpEnable int NOT NULL,
|
||||
rtpPortRange varchar(50) NOT NULL,
|
||||
recordAssistPort int NOT NULL,
|
||||
createTime varchar(50) not null,
|
||||
updateTime varchar(50) not null
|
||||
);
|
@ -12,6 +12,8 @@ public class VideoManagerConstants {
|
||||
|
||||
public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_";
|
||||
|
||||
public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS";
|
||||
|
||||
public static final String MEDIA_STREAM_PREFIX = "VMP_MEDIA_STREAM";
|
||||
|
||||
public static final String DEVICE_PREFIX = "VMP_DEVICE_";
|
||||
@ -45,4 +47,8 @@ public class VideoManagerConstants {
|
||||
public static final String EVENT_OUTLINE_UNREGISTER = "1";
|
||||
|
||||
public static final String EVENT_OUTLINE_TIMEOUT = "2";
|
||||
|
||||
public static final String MEDIA_SSRC_USED_PREFIX = "VMP_media_used_ssrc_";
|
||||
|
||||
public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_media_transaction_";
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
@Configuration("mediaConfig")
|
||||
public class MediaConfig implements IMediaServerItem {
|
||||
public class MediaConfig{
|
||||
|
||||
@Value("${media.id:}")
|
||||
private String id;
|
||||
@ -21,6 +24,9 @@ public class MediaConfig implements IMediaServerItem {
|
||||
@Value("${sip.ip}")
|
||||
private String sipIp;
|
||||
|
||||
@Value("${sip.domain}")
|
||||
private String sipDomain;
|
||||
|
||||
@Value("${media.sdp-ip:${media.ip}}")
|
||||
private String sdpIp;
|
||||
|
||||
@ -66,31 +72,14 @@ public class MediaConfig implements IMediaServerItem {
|
||||
@Value("${media.record-assist-port:0}")
|
||||
private Integer recordAssistPort = 0;
|
||||
|
||||
private String updateTime;
|
||||
|
||||
private String createTime;
|
||||
|
||||
private boolean docker = false;
|
||||
|
||||
private int count;
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public String getHookIp() {
|
||||
if (StringUtils.isEmpty(hookIp)){
|
||||
return sipIp;
|
||||
@ -100,78 +89,26 @@ public class MediaConfig implements IMediaServerItem {
|
||||
|
||||
}
|
||||
|
||||
public void setHookIp(String hookIp) {
|
||||
this.hookIp = hookIp;
|
||||
}
|
||||
|
||||
public String getSipIp() {
|
||||
return sipIp;
|
||||
}
|
||||
|
||||
public void setSipIp(String sipIp) {
|
||||
this.sipIp = sipIp;
|
||||
}
|
||||
|
||||
public void setSdpIp(String sdpIp) {
|
||||
this.sdpIp = sdpIp;
|
||||
}
|
||||
|
||||
public void setStreamIp(String streamIp) {
|
||||
this.streamIp = streamIp;
|
||||
}
|
||||
|
||||
public int getHttpPort() {
|
||||
return httpPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHttpPort(int httpPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setHttpPort(Integer httpPort) {
|
||||
this.httpPort = httpPort;
|
||||
}
|
||||
|
||||
public int getHttpSSlPort() {
|
||||
return httpSSlPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHttpSSlPort(int httpSSlPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setHttpSSlPort(Integer httpSSlPort) {
|
||||
this.httpSSlPort = httpSSlPort;
|
||||
}
|
||||
|
||||
public int getRtmpPort() {
|
||||
return rtmpPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRtmpPort(int rtmpPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRtmpPort(Integer rtmpPort) {
|
||||
this.rtmpPort = rtmpPort;
|
||||
}
|
||||
|
||||
public int getRtmpSSlPort() {
|
||||
return rtmpSSlPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRtmpSSlPort(int rtmpSSlPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRtmpSSlPort(Integer rtmpSSlPort) {
|
||||
this.rtmpSSlPort = rtmpSSlPort;
|
||||
}
|
||||
|
||||
public int getRtpProxyPort() {
|
||||
if (rtpProxyPort == null) {
|
||||
return 0;
|
||||
@ -181,104 +118,38 @@ public class MediaConfig implements IMediaServerItem {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRtpProxyPort(int rtpProxyPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRtpProxyPort(Integer rtpProxyPort) {
|
||||
this.rtpProxyPort = rtpProxyPort;
|
||||
}
|
||||
|
||||
public int getRtspPort() {
|
||||
return rtspPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRtspPort(int rtspPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRtspPort(Integer rtspPort) {
|
||||
this.rtspPort = rtspPort;
|
||||
}
|
||||
|
||||
public int getRtspSSLPort() {
|
||||
return rtspSSLPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRtspSSLPort(int rtspSSLPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRtspSSLPort(Integer rtspSSLPort) {
|
||||
this.rtspSSLPort = rtspSSLPort;
|
||||
}
|
||||
|
||||
public boolean isAutoConfig() {
|
||||
return autoConfig;
|
||||
}
|
||||
|
||||
public void setAutoConfig(boolean autoConfig) {
|
||||
this.autoConfig = autoConfig;
|
||||
}
|
||||
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
public String getStreamNoneReaderDelayMS() {
|
||||
return streamNoneReaderDelayMS;
|
||||
}
|
||||
|
||||
public void setStreamNoneReaderDelayMS(String streamNoneReaderDelayMS) {
|
||||
this.streamNoneReaderDelayMS = streamNoneReaderDelayMS;
|
||||
}
|
||||
|
||||
public boolean isRtpEnable() {
|
||||
return rtpEnable;
|
||||
}
|
||||
|
||||
public void setRtpEnable(boolean rtpEnable) {
|
||||
this.rtpEnable = rtpEnable;
|
||||
}
|
||||
|
||||
public String getRtpPortRange() {
|
||||
return rtpPortRange;
|
||||
}
|
||||
|
||||
public void setRtpPortRange(String rtpPortRange) {
|
||||
this.rtpPortRange = rtpPortRange;
|
||||
}
|
||||
|
||||
public int getRecordAssistPort() {
|
||||
return recordAssistPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecordAssistPort(int recordAssistPort) {
|
||||
|
||||
}
|
||||
|
||||
public void setRecordAssistPort(Integer recordAssistPort) {
|
||||
this.recordAssistPort = recordAssistPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDocker() {
|
||||
return docker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDocker(boolean docker) {
|
||||
this.docker = docker;
|
||||
}
|
||||
|
||||
public String getSdpIp() {
|
||||
if (StringUtils.isEmpty(sdpIp)){
|
||||
return ip;
|
||||
@ -295,13 +166,11 @@ public class MediaConfig implements IMediaServerItem {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public MediaServerItem getMediaSerItem(){
|
||||
MediaServerItem mediaServerItem = new MediaServerItem();
|
||||
mediaServerItem.setId(id);
|
||||
mediaServerItem.setIp(ip);
|
||||
mediaServerItem.setDocker(true);
|
||||
mediaServerItem.setDefaultServer(true);
|
||||
mediaServerItem.setHookIp(hookIp);
|
||||
mediaServerItem.setSdpIp(sdpIp);
|
||||
mediaServerItem.setStreamIp(streamIp);
|
||||
@ -318,39 +187,12 @@ public class MediaConfig implements IMediaServerItem {
|
||||
mediaServerItem.setRtpEnable(rtpEnable);
|
||||
mediaServerItem.setRtpPortRange(rtpPortRange);
|
||||
mediaServerItem.setRecordAssistPort(recordAssistPort);
|
||||
mediaServerItem.setCreateTime(createTime);
|
||||
mediaServerItem.setUpdateTime(updateTime);
|
||||
mediaServerItem.setCount(count);
|
||||
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
mediaServerItem.setCreateTime(format.format(new Date(System.currentTimeMillis())));
|
||||
mediaServerItem.setUpdateTime(format.format(new Date(System.currentTimeMillis())));
|
||||
|
||||
return mediaServerItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUpdateTime(String updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateTime(String createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import org.apache.catalina.connector.ClientAbortException;
|
||||
import org.apache.http.HttpHost;
|
||||
@ -49,7 +49,7 @@ public class ProxyServletConfig {
|
||||
@Override
|
||||
protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
|
||||
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
|
||||
IMediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
|
||||
MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
|
||||
if (mediaInfo != null) {
|
||||
if (!StringUtils.isEmpty(queryStr)) {
|
||||
queryStr += "&secret=" + mediaInfo.getSecret();
|
||||
@ -88,7 +88,7 @@ public class ProxyServletConfig {
|
||||
@Override
|
||||
protected String getTargetUri(HttpServletRequest servletRequest) {
|
||||
String requestURI = servletRequest.getRequestURI();
|
||||
IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
|
||||
String uri = null;
|
||||
if (mediaInfo != null) {
|
||||
@ -106,7 +106,7 @@ public class ProxyServletConfig {
|
||||
@Override
|
||||
protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
|
||||
String requestURI = servletRequest.getRequestURI();
|
||||
IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
HttpHost host;
|
||||
if (mediaInfo != null) {
|
||||
host = new HttpHost(mediaInfo.getIp(), mediaInfo.getHttpPort());
|
||||
@ -120,7 +120,7 @@ public class ProxyServletConfig {
|
||||
/**
|
||||
* 根据uri获取流媒体信息
|
||||
*/
|
||||
IMediaServerItem getMediaInfoByUri(String uri){
|
||||
MediaServerItem getMediaInfoByUri(String uri){
|
||||
String[] split = uri.split("/");
|
||||
String mediaServerId = split[2];
|
||||
return mediaServerService.getOne(mediaServerId);
|
||||
@ -132,7 +132,7 @@ public class ProxyServletConfig {
|
||||
@Override
|
||||
protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
|
||||
String requestURI = servletRequest.getRequestURI();
|
||||
IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
String url = super.rewriteUrlFromRequest(servletRequest);
|
||||
if (mediaInfo == null) {
|
||||
return url;
|
||||
@ -186,7 +186,7 @@ public class ProxyServletConfig {
|
||||
@Override
|
||||
protected String getTargetUri(HttpServletRequest servletRequest) {
|
||||
String requestURI = servletRequest.getRequestURI();
|
||||
IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
|
||||
String uri = null;
|
||||
if (mediaInfo != null) {
|
||||
@ -204,7 +204,7 @@ public class ProxyServletConfig {
|
||||
@Override
|
||||
protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
|
||||
String requestURI = servletRequest.getRequestURI();
|
||||
IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
HttpHost host;
|
||||
if (mediaInfo != null) {
|
||||
host = new HttpHost(mediaInfo.getIp(), mediaInfo.getRecordAssistPort());
|
||||
@ -218,7 +218,7 @@ public class ProxyServletConfig {
|
||||
/**
|
||||
* 根据uri获取流媒体信息
|
||||
*/
|
||||
IMediaServerItem getMediaInfoByUri(String uri){
|
||||
MediaServerItem getMediaInfoByUri(String uri){
|
||||
String[] split = uri.split("/");
|
||||
String mediaServerId = split[2];
|
||||
return mediaServerService.getOne(mediaServerId);
|
||||
@ -230,7 +230,7 @@ public class ProxyServletConfig {
|
||||
@Override
|
||||
protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
|
||||
String requestURI = servletRequest.getRequestURI();
|
||||
IMediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
|
||||
String url = super.rewriteUrlFromRequest(servletRequest);
|
||||
if (mediaInfo == null) {
|
||||
return url;
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -10,6 +12,8 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
/**
|
||||
* @Description:Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置
|
||||
@ -20,6 +24,37 @@ import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
|
||||
@Configuration
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
@Value("${spring.redis.host}")
|
||||
private String host;
|
||||
@Value("${spring.redis.port}")
|
||||
private int port;
|
||||
@Value("${spring.redis.database}")
|
||||
private int database;
|
||||
@Value("${spring.redis.password}")
|
||||
private String password;
|
||||
@Value("${spring.redis.timeout}")
|
||||
private int timeout;
|
||||
@Value("${spring.redis.poolMaxTotal:1000}")
|
||||
private int poolMaxTotal;
|
||||
@Value("${spring.redis.poolMaxIdle:500}")
|
||||
private int poolMaxIdle;
|
||||
@Value("${spring.redis.poolMaxWait:5}")
|
||||
private int poolMaxWait;
|
||||
|
||||
@Bean
|
||||
public JedisPool jedisPool() {
|
||||
if (StringUtils.isBlank(password)) {
|
||||
password = null;
|
||||
}
|
||||
JedisPoolConfig poolConfig = new JedisPoolConfig();
|
||||
poolConfig.setMaxIdle(poolMaxIdle);
|
||||
poolConfig.setMaxTotal(poolMaxTotal);
|
||||
// 秒转毫秒
|
||||
poolConfig.setMaxWaitMillis(poolMaxWait * 1000L);
|
||||
JedisPool jp = new JedisPool(poolConfig, host, port, timeout * 1000, password, database);
|
||||
return jp;
|
||||
}
|
||||
|
||||
@Bean("redisTemplate")
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||
|
@ -1,31 +0,0 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* 系统启动时控制设备离线
|
||||
*/
|
||||
@Component
|
||||
@Order(value=4)
|
||||
public class SipDeviceRunner implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorager storager;
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
// 设置所有设备离线
|
||||
storager.outlineForAll();
|
||||
// 设置所有设备离线
|
||||
redisCatchStorage.outlineForAll();
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import javax.sip.header.CallIdHeader;
|
||||
import javax.sip.message.Response;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import gov.nist.javax.sip.SipProviderImpl;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -39,7 +40,7 @@ public class SipLayer implements SipListener {
|
||||
@Autowired
|
||||
private SipSubscribe sipSubscribe;
|
||||
|
||||
private SipStack sipStack;
|
||||
private SipStackImpl sipStack;
|
||||
|
||||
private SipFactory sipFactory;
|
||||
|
||||
@ -52,7 +53,7 @@ public class SipLayer implements SipListener {
|
||||
private ThreadPoolExecutor initSipServer() {
|
||||
|
||||
int processThreadNum = Runtime.getRuntime().availableProcessors() * 10;
|
||||
LinkedBlockingQueue<Runnable> processQueue = new LinkedBlockingQueue<Runnable>(10000);
|
||||
LinkedBlockingQueue<Runnable> processQueue = new LinkedBlockingQueue<>(10000);
|
||||
processThreadPool = new ThreadPoolExecutor(processThreadNum,processThreadNum,
|
||||
0L,TimeUnit.MILLISECONDS,processQueue,
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
@ -88,17 +89,14 @@ public class SipLayer implements SipListener {
|
||||
|
||||
@Bean("tcpSipProvider")
|
||||
@DependsOn("sipStack")
|
||||
private SipProvider startTcpListener() {
|
||||
private SipProviderImpl startTcpListener() {
|
||||
ListeningPoint tcpListeningPoint = null;
|
||||
SipProvider tcpSipProvider = null;
|
||||
SipProviderImpl tcpSipProvider = null;
|
||||
try {
|
||||
tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "TCP");
|
||||
tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint);
|
||||
tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint);
|
||||
tcpSipProvider.addSipListener(this);
|
||||
logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getMonitorIp() + ":" + sipConfig.getSipPort() + "}");
|
||||
// } catch (TransportNotSupportedException | InvalidArgumentException | TooManyListenersException | ObjectInUseException e) {
|
||||
// logger.error(String.format("创建SIP服务失败: %s", e.getMessage()));
|
||||
// }
|
||||
} catch (TransportNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidArgumentException e) {
|
||||
@ -114,13 +112,14 @@ public class SipLayer implements SipListener {
|
||||
|
||||
@Bean("udpSipProvider")
|
||||
@DependsOn("sipStack")
|
||||
private SipProvider startUdpListener() {
|
||||
private SipProviderImpl startUdpListener() {
|
||||
ListeningPoint udpListeningPoint = null;
|
||||
SipProvider udpSipProvider = null;
|
||||
SipProviderImpl udpSipProvider = null;
|
||||
try {
|
||||
udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "UDP");
|
||||
udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
|
||||
udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint);
|
||||
udpSipProvider.addSipListener(this);
|
||||
// udpSipProvider.setAutomaticDialogSupportEnabled(false);
|
||||
} catch (TransportNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidArgumentException e) {
|
||||
@ -141,7 +140,7 @@ public class SipLayer implements SipListener {
|
||||
*/
|
||||
@Override
|
||||
public void processRequest(RequestEvent evt) {
|
||||
// logger.debug(evt.getRequest().toString());
|
||||
logger.debug(evt.getRequest().toString());
|
||||
// 由于jainsip是单线程程序,为提高性能并发处理
|
||||
processThreadPool.execute(() -> {
|
||||
if (processorFactory != null) {
|
||||
@ -153,7 +152,7 @@ public class SipLayer implements SipListener {
|
||||
@Override
|
||||
public void processResponse(ResponseEvent evt) {
|
||||
Response response = evt.getResponse();
|
||||
// logger.debug(evt.getResponse().toString());
|
||||
logger.debug(evt.getResponse().toString());
|
||||
int status = response.getStatusCode();
|
||||
if (((status >= 200) && (status < 300)) || status == 401) { // Success!
|
||||
ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
|
||||
@ -163,6 +162,7 @@ public class SipLayer implements SipListener {
|
||||
// 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) {
|
||||
@ -220,7 +220,6 @@ public class SipLayer implements SipListener {
|
||||
@Override
|
||||
public void processIOException(IOExceptionEvent exceptionEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -236,7 +235,6 @@ public class SipLayer implements SipListener {
|
||||
@Override
|
||||
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,70 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
import javax.sip.message.Request;
|
||||
|
||||
public class SsrcTransaction {
|
||||
|
||||
private String deviceId;
|
||||
private String channelId;
|
||||
private String ssrc;
|
||||
private String streamId;
|
||||
private byte[] transaction;
|
||||
private byte[] dialog;
|
||||
private String mediaServerId;
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public String getChannelId() {
|
||||
return channelId;
|
||||
}
|
||||
|
||||
public void setChannelId(String channelId) {
|
||||
this.channelId = channelId;
|
||||
}
|
||||
|
||||
public String getSsrc() {
|
||||
return ssrc;
|
||||
}
|
||||
|
||||
public void setSsrc(String ssrc) {
|
||||
this.ssrc = ssrc;
|
||||
}
|
||||
|
||||
public String getStreamId() {
|
||||
return streamId;
|
||||
}
|
||||
|
||||
public void setStreamId(String streamId) {
|
||||
this.streamId = streamId;
|
||||
}
|
||||
|
||||
public byte[] getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public void setTransaction(byte[] transaction) {
|
||||
this.transaction = transaction;
|
||||
}
|
||||
|
||||
public byte[] getDialog() {
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public void setDialog(byte[] dialog) {
|
||||
this.dialog = dialog;
|
||||
}
|
||||
|
||||
public String getMediaServerId() {
|
||||
return mediaServerId;
|
||||
}
|
||||
|
||||
public void setMediaServerId(String mediaServerId) {
|
||||
this.mediaServerId = mediaServerId;
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
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.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
@ -77,7 +76,7 @@ public class PlatformNotRegisterEventLister implements ApplicationListener<Platf
|
||||
}
|
||||
stream.append(sendRtpItem.getStreamId());
|
||||
redisCatchStorage.deleteSendRTPServer(event.getPlatformGbID(), sendRtpItem.getChannelId());
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("vhost", "__defaultVhost__");
|
||||
param.put("app", app.toString());
|
||||
|
@ -0,0 +1,140 @@
|
||||
package com.genersoft.iot.vmp.gb28181.session;
|
||||
|
||||
import com.genersoft.iot.vmp.utils.ConfigConst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
public class SsrcConfig {
|
||||
|
||||
/**
|
||||
* zlm流媒体服务器Id
|
||||
*/
|
||||
private String mediaServerId;
|
||||
|
||||
private String ssrcPrefix;
|
||||
/**
|
||||
* zlm流媒体服务器已用会话句柄
|
||||
*/
|
||||
private List<String> isUsed;
|
||||
/**
|
||||
* zlm流媒体服务器可用会话句柄
|
||||
*/
|
||||
private List<String> notUsed;
|
||||
|
||||
public SsrcConfig() {
|
||||
}
|
||||
|
||||
public SsrcConfig(String mediaServerId, Set<String> usedSet, String sipDomain) {
|
||||
this.mediaServerId = mediaServerId;
|
||||
this.isUsed = new ArrayList<>();
|
||||
this.ssrcPrefix = sipDomain.substring(3, 8);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取视频预览的SSRC值,第一位固定为0
|
||||
* @return ssrc
|
||||
*/
|
||||
public String getPlaySsrc() {
|
||||
return "0" + getSsrcPrefix() + getSN();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取录像回放的SSRC值,第一位固定为1
|
||||
*
|
||||
*/
|
||||
public String getPlayBackSsrc() {
|
||||
return "1" + getSsrcPrefix() + getSN();
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放ssrc,主要用完的ssrc一定要释放,否则会耗尽
|
||||
* @param ssrc 需要重置的ssrc
|
||||
*/
|
||||
public void releaseSsrc(String ssrc) {
|
||||
if (ssrc == null) {
|
||||
return;
|
||||
}
|
||||
String sn = ssrc.substring(6);
|
||||
try {
|
||||
isUsed.remove(sn);
|
||||
notUsed.add(sn);
|
||||
}catch (NullPointerException e){
|
||||
System.out.printf("11111");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取后四位数SN,随机数
|
||||
*
|
||||
*/
|
||||
private 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;
|
||||
}
|
||||
|
||||
public String getSsrcPrefix() {
|
||||
return ssrcPrefix;
|
||||
}
|
||||
|
||||
public String getMediaServerId() {
|
||||
return mediaServerId;
|
||||
}
|
||||
|
||||
public void setMediaServerId(String mediaServerId) {
|
||||
this.mediaServerId = mediaServerId;
|
||||
}
|
||||
|
||||
public void setSsrcPrefix(String ssrcPrefix) {
|
||||
this.ssrcPrefix = ssrcPrefix;
|
||||
}
|
||||
|
||||
public List<String> getIsUsed() {
|
||||
return isUsed;
|
||||
}
|
||||
|
||||
public void setIsUsed(List<String> isUsed) {
|
||||
this.isUsed = isUsed;
|
||||
}
|
||||
|
||||
public List<String> getNotUsed() {
|
||||
return notUsed;
|
||||
}
|
||||
|
||||
public void setNotUsed(List<String> notUsed) {
|
||||
this.notUsed = notUsed;
|
||||
}
|
||||
|
||||
}
|
@ -1,101 +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;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @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 final static Logger logger = LoggerFactory.getLogger(SsrcUtil.class);
|
||||
|
||||
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) {
|
||||
if (ssrc == null) {
|
||||
logger.error("要释放ssrc为null");
|
||||
return;
|
||||
}
|
||||
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,9 +1,23 @@
|
||||
package com.genersoft.iot.vmp.gb28181.session;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.sip.ClientTransaction;
|
||||
import javax.sip.Dialog;
|
||||
import javax.sip.message.Request;
|
||||
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.utils.SerializeUtils;
|
||||
import com.genersoft.iot.vmp.utils.redis.JedisUtil;
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||
import gov.nist.javax.sip.stack.SIPDialog;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -14,50 +28,85 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class VideoStreamSessionManager {
|
||||
|
||||
private ConcurrentHashMap<String, ClientTransaction> sessionMap = new ConcurrentHashMap<>();
|
||||
private ConcurrentHashMap<String, String> ssrcMap = new ConcurrentHashMap<>();
|
||||
private ConcurrentHashMap<String, String> streamIdMap = new ConcurrentHashMap<>();
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
public String createPlaySsrc(){
|
||||
return SsrcUtil.getPlaySsrc();
|
||||
public void put(String deviceId, String channelId ,String ssrc, String streamId, String mediaServerId, ClientTransaction transaction){
|
||||
SsrcTransaction ssrcTransaction = new SsrcTransaction();
|
||||
ssrcTransaction.setDeviceId(deviceId);
|
||||
ssrcTransaction.setChannelId(channelId);
|
||||
ssrcTransaction.setStreamId(streamId);
|
||||
byte[] transactionByteArray = SerializeUtils.serialize(transaction);
|
||||
ssrcTransaction.setTransaction(transactionByteArray);
|
||||
ssrcTransaction.setSsrc(ssrc);
|
||||
ssrcTransaction.setMediaServerId(mediaServerId);
|
||||
|
||||
redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + deviceId + "_" + channelId, ssrcTransaction);
|
||||
}
|
||||
|
||||
public String createPlayBackSsrc(){
|
||||
return SsrcUtil.getPlayBackSsrc();
|
||||
public void put(String deviceId, String channelId , Dialog dialog){
|
||||
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
|
||||
if (ssrcTransaction != null) {
|
||||
byte[] dialogByteArray = SerializeUtils.serialize(dialog);
|
||||
ssrcTransaction.setDialog(dialogByteArray);
|
||||
}
|
||||
redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + deviceId + "_" + channelId, ssrcTransaction);
|
||||
}
|
||||
|
||||
public void put(String deviceId, String channelId ,String ssrc, String streamId, ClientTransaction transaction){
|
||||
sessionMap.put(deviceId + "_" + channelId, transaction);
|
||||
ssrcMap.put(deviceId + "_" + channelId, ssrc);
|
||||
streamIdMap.put(deviceId + "_" + channelId, streamId);
|
||||
}
|
||||
|
||||
public ClientTransaction getTransaction(String deviceId, String channelId){
|
||||
return sessionMap.get(deviceId + "_" + channelId);
|
||||
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
|
||||
if (ssrcTransaction == null) return null;
|
||||
byte[] transactionByteArray = ssrcTransaction.getTransaction();
|
||||
ClientTransaction clientTransaction = (ClientTransaction)SerializeUtils.deSerialize(transactionByteArray);
|
||||
return clientTransaction;
|
||||
}
|
||||
|
||||
public SIPDialog getDialog(String deviceId, String channelId){
|
||||
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
|
||||
if (ssrcTransaction == null) return null;
|
||||
byte[] dialogByteArray = ssrcTransaction.getDialog();
|
||||
if (dialogByteArray == null) return null;
|
||||
SIPDialog dialog = (SIPDialog)SerializeUtils.deSerialize(dialogByteArray);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public SsrcTransaction getSsrcTransaction(String deviceId, String channelId){
|
||||
SsrcTransaction ssrcTransaction = (SsrcTransaction)redisUtil.get(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + deviceId + "_" + channelId);
|
||||
return ssrcTransaction;
|
||||
}
|
||||
|
||||
public String getStreamId(String deviceId, String channelId){
|
||||
return streamIdMap.get(deviceId + "_" + channelId);
|
||||
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
|
||||
if (ssrcTransaction == null) return null;
|
||||
return ssrcTransaction.getStreamId();
|
||||
}
|
||||
public String getMediaServerId(String deviceId, String channelId){
|
||||
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
|
||||
if (ssrcTransaction == null) return null;
|
||||
return ssrcTransaction.getMediaServerId();
|
||||
}
|
||||
|
||||
public String getSSRC(String deviceId, String channelId){
|
||||
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
|
||||
if (ssrcTransaction == null) return null;
|
||||
return ssrcTransaction.getSsrc();
|
||||
}
|
||||
|
||||
public void remove(String deviceId, String channelId) {
|
||||
sessionMap.remove(deviceId + "_" + channelId);
|
||||
if (ssrcMap.get(deviceId + "_" + channelId) != null) {
|
||||
SsrcUtil.releaseSsrc(ssrcMap.get(deviceId + "_" + channelId));
|
||||
}
|
||||
ssrcMap.remove(deviceId + "_" + channelId);
|
||||
streamIdMap.remove(deviceId + "_" + channelId);
|
||||
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
|
||||
if (ssrcTransaction == null) return;
|
||||
redisUtil.del(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + deviceId + "_" + channelId);
|
||||
}
|
||||
|
||||
public ConcurrentHashMap<String, ClientTransaction> getSessionMap() {
|
||||
return sessionMap;
|
||||
public List<SsrcTransaction> getAllSsrc() {
|
||||
List<Object> ssrcTransactionKeys = redisUtil.scan(String.format("%s_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX));
|
||||
List<SsrcTransaction> result= new ArrayList<>();
|
||||
for (int i = 0; i < ssrcTransactionKeys.size(); i++) {
|
||||
String key = (String)ssrcTransactionKeys.get(i);
|
||||
SsrcTransaction ssrcTransaction = (SsrcTransaction)redisUtil.get(key);
|
||||
result.add(ssrcTransaction);
|
||||
}
|
||||
|
||||
public ConcurrentHashMap<String, String> getSsrcMap() {
|
||||
return ssrcMap;
|
||||
}
|
||||
|
||||
public ConcurrentHashMap<String, String> getStreamIdMap() {
|
||||
return streamIdMap;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import javax.sip.header.CSeqHeader;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
@ -108,7 +109,6 @@ public class SIPProcessorFactory {
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
|
||||
// 注:这里使用注解会导致循环依赖注入,暂用springBean
|
||||
private SipProvider tcpSipProvider;
|
||||
|
||||
|
@ -3,8 +3,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
|
||||
/**
|
||||
* @Description:设备能力接口,用于定义设备的控制、查询能力
|
||||
@ -92,7 +92,7 @@ public interface ISIPCommander {
|
||||
* @param device 视频设备
|
||||
* @param channelId 预览通道
|
||||
*/
|
||||
void playStreamCmd(IMediaServerItem mediaServerItem, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
|
||||
/**
|
||||
* 请求回放视频流
|
||||
@ -102,7 +102,7 @@ public interface ISIPCommander {
|
||||
* @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
void playbackStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
|
||||
/**
|
||||
* 请求历史媒体下载
|
||||
@ -113,12 +113,10 @@ public interface ISIPCommander {
|
||||
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||
* @param downloadSpeed 下载倍速参数
|
||||
*/
|
||||
void downloadStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
|
||||
/**
|
||||
* 视频流停止
|
||||
*
|
||||
* @param ssrc ssrc
|
||||
*/
|
||||
void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent);
|
||||
void streamByeCmd(String deviceId, String channelId);
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.text.ParseException;
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.sip.*;
|
||||
import javax.sip.address.SipURI;
|
||||
@ -8,18 +10,21 @@ import javax.sip.header.CallIdHeader;
|
||||
import javax.sip.header.ViaHeader;
|
||||
import javax.sip.message.Request;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetup;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
|
||||
import com.genersoft.iot.vmp.media.zlm.*;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import gov.nist.javax.sip.SipProviderImpl;
|
||||
import gov.nist.javax.sip.SipStackImpl;
|
||||
import gov.nist.javax.sip.message.SIPRequest;
|
||||
import gov.nist.javax.sip.stack.SIPDialog;
|
||||
import gov.nist.javax.sip.stack.SIPTransaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -35,7 +40,6 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@ -55,12 +59,12 @@ public class SIPCommander implements ISIPCommander {
|
||||
@Lazy
|
||||
@Autowired
|
||||
@Qualifier(value="tcpSipProvider")
|
||||
private SipProvider tcpSipProvider;
|
||||
private SipProviderImpl tcpSipProvider;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
@Qualifier(value="udpSipProvider")
|
||||
private SipProvider udpSipProvider;
|
||||
private SipProviderImpl udpSipProvider;
|
||||
|
||||
@Autowired
|
||||
private SIPRequestHeaderProvider headerProvider;
|
||||
@ -74,9 +78,6 @@ public class SIPCommander implements ISIPCommander {
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
@Autowired
|
||||
private UserSetup userSetup;
|
||||
|
||||
@ -86,6 +87,11 @@ public class SIPCommander implements ISIPCommander {
|
||||
@Autowired
|
||||
private SipSubscribe sipSubscribe;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
private SIPDialog dialog;
|
||||
|
||||
public SipConfig getSipConfig() {
|
||||
return sipConfig;
|
||||
}
|
||||
@ -334,26 +340,13 @@ public class SIPCommander implements ISIPCommander {
|
||||
* @param errorEvent sip错误订阅
|
||||
*/
|
||||
@Override
|
||||
public void playStreamCmd(IMediaServerItem mediaServerItem, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
|
||||
String streamId = null;
|
||||
public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
|
||||
String streamId = ssrcInfo.getStreamId();
|
||||
try {
|
||||
if (device == null) return;
|
||||
String streamMode = device.getStreamMode().toUpperCase();
|
||||
|
||||
String ssrc = streamSession.createPlaySsrc();
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
|
||||
}else {
|
||||
streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
|
||||
}
|
||||
Integer mediaPort = null;
|
||||
// 使用动态udp端口
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId);
|
||||
}else {
|
||||
mediaPort = mediaServerItem.getRtpProxyPort();
|
||||
}
|
||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort);
|
||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
|
||||
// 添加订阅
|
||||
JSONObject subscribeKey = new JSONObject();
|
||||
subscribeKey.put("app", "rtp");
|
||||
@ -361,7 +354,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
subscribeKey.put("regist", true);
|
||||
subscribeKey.put("mediaServerId", mediaServerItem.getId());
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
||||
(IMediaServerItem mediaServerItemInUse, JSONObject json)->{
|
||||
(MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
||||
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
|
||||
event.response(mediaServerItemInUse, json);
|
||||
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
|
||||
@ -369,7 +362,6 @@ public class SIPCommander implements ISIPCommander {
|
||||
//
|
||||
StringBuffer content = new StringBuffer(200);
|
||||
content.append("v=0\r\n");
|
||||
// content.append("o=" + sipConfig.getSipId() + " 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
|
||||
content.append("o="+"00000"+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
|
||||
content.append("s=Play\r\n");
|
||||
content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
|
||||
@ -377,11 +369,11 @@ public class SIPCommander implements ISIPCommander {
|
||||
|
||||
if (userSetup.isSeniorSdp()) {
|
||||
if("TCP-PASSIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
}else if ("TCP-ACTIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
}else if("UDP".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
}
|
||||
content.append("a=recvonly\r\n");
|
||||
content.append("a=rtpmap:96 PS/90000\r\n");
|
||||
@ -402,11 +394,11 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
}else {
|
||||
if("TCP-PASSIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
}else if ("TCP-ACTIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
}else if("UDP".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n");
|
||||
}
|
||||
content.append("a=recvonly\r\n");
|
||||
content.append("a=rtpmap:96 PS/90000\r\n");
|
||||
@ -421,20 +413,25 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
}
|
||||
|
||||
content.append("y="+ssrc+"\r\n");//ssrc
|
||||
content.append("y="+ssrcInfo.getSsrc()+"\r\n");//ssrc
|
||||
|
||||
String tm = Long.toString(System.currentTimeMillis());
|
||||
|
||||
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
|
||||
: udpSipProvider.getNewCallId();
|
||||
|
||||
Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrc, callIdHeader);
|
||||
Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrcInfo.getSsrc(), callIdHeader);
|
||||
|
||||
ClientTransaction transaction = transmitRequest(device, request, (e -> {
|
||||
String finalStreamId = streamId;
|
||||
transmitRequest(device, request, (e -> {
|
||||
streamSession.remove(device.getDeviceId(), channelId);
|
||||
mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc());
|
||||
errorEvent.response(e);
|
||||
}));
|
||||
streamSession.put(device.getDeviceId(), channelId ,ssrc,streamId, transaction);
|
||||
}), e ->{
|
||||
streamSession.put(device.getDeviceId(), channelId ,ssrcInfo.getSsrc(), finalStreamId, mediaServerItem.getId(),e.getClientTransaction());
|
||||
streamSession.put(device.getDeviceId(), channelId , e.getDialog());
|
||||
});
|
||||
|
||||
|
||||
} catch ( SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
@ -450,30 +447,21 @@ public class SIPCommander implements ISIPCommander {
|
||||
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
@Override
|
||||
public void playbackStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
|
||||
public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
|
||||
, SipSubscribe.Event errorEvent) {
|
||||
try {
|
||||
String ssrc = streamSession.createPlayBackSsrc();
|
||||
String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
|
||||
|
||||
Integer mediaPort = null;
|
||||
// 使用动态udp端口
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId);
|
||||
}else {
|
||||
mediaPort = mediaServerItem.getRtpProxyPort();
|
||||
}
|
||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort);
|
||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
|
||||
|
||||
// 添加订阅
|
||||
JSONObject subscribeKey = new JSONObject();
|
||||
subscribeKey.put("app", "rtp");
|
||||
subscribeKey.put("stream", streamId);
|
||||
subscribeKey.put("stream", ssrcInfo.getStreamId());
|
||||
subscribeKey.put("regist", true);
|
||||
subscribeKey.put("mediaServerId", mediaServerItem.getId());
|
||||
logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
||||
(IMediaServerItem mediaServerItemInUse, JSONObject json)->{
|
||||
(MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
||||
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
|
||||
event.response(mediaServerItemInUse, json);
|
||||
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
|
||||
@ -494,11 +482,11 @@ public class SIPCommander implements ISIPCommander {
|
||||
|
||||
if (userSetup.isSeniorSdp()) {
|
||||
if("TCP-PASSIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
}else if ("TCP-ACTIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
}else if("UDP".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
}
|
||||
content.append("a=recvonly\r\n");
|
||||
content.append("a=rtpmap:96 PS/90000\r\n");
|
||||
@ -519,11 +507,11 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
}else {
|
||||
if("TCP-PASSIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
}else if ("TCP-ACTIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
}else if("UDP".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n");
|
||||
}
|
||||
content.append("a=recvonly\r\n");
|
||||
content.append("a=rtpmap:96 PS/90000\r\n");
|
||||
@ -538,7 +526,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
}
|
||||
|
||||
content.append("y="+ssrc+"\r\n");//ssrc
|
||||
content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
|
||||
|
||||
String tm = Long.toString(System.currentTimeMillis());
|
||||
|
||||
@ -547,9 +535,11 @@ public class SIPCommander implements ISIPCommander {
|
||||
|
||||
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader);
|
||||
|
||||
ClientTransaction transaction = transmitRequest(device, request, errorEvent);
|
||||
streamSession.put(device.getDeviceId(), channelId, ssrc, streamId, transaction);
|
||||
|
||||
transmitRequest(device, request, errorEvent, okEvent -> {
|
||||
Dialog dialog = okEvent.getClientTransaction().getDialog();
|
||||
streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), okEvent.getClientTransaction());
|
||||
streamSession.put(device.getDeviceId(), channelId, dialog);
|
||||
});
|
||||
} catch ( SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -565,30 +555,20 @@ public class SIPCommander implements ISIPCommander {
|
||||
* @param downloadSpeed 下载倍速参数
|
||||
*/
|
||||
@Override
|
||||
public void downloadStreamCmd(IMediaServerItem mediaServerItem,Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event
|
||||
public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event
|
||||
, SipSubscribe.Event errorEvent) {
|
||||
try {
|
||||
String ssrc = streamSession.createPlayBackSsrc();
|
||||
String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
|
||||
|
||||
Integer mediaPort = null;
|
||||
// 使用动态udp端口
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
mediaPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId);
|
||||
}else {
|
||||
mediaPort = mediaServerItem.getRtpProxyPort();
|
||||
}
|
||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), mediaPort);
|
||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
|
||||
|
||||
// 添加订阅
|
||||
JSONObject subscribeKey = new JSONObject();
|
||||
subscribeKey.put("app", "rtp");
|
||||
subscribeKey.put("stream", streamId);
|
||||
subscribeKey.put("stream", ssrcInfo.getStreamId());
|
||||
subscribeKey.put("regist", true);
|
||||
subscribeKey.put("mediaServerId", mediaServerItem.getId());
|
||||
logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
||||
(IMediaServerItem mediaServerItemInUse, JSONObject json)->{
|
||||
(MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
||||
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
|
||||
event.response(mediaServerItemInUse, json);
|
||||
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
|
||||
@ -609,11 +589,11 @@ public class SIPCommander implements ISIPCommander {
|
||||
|
||||
if (userSetup.isSeniorSdp()) {
|
||||
if("TCP-PASSIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
}else if ("TCP-ACTIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
}else if("UDP".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
}
|
||||
content.append("a=recvonly\r\n");
|
||||
content.append("a=rtpmap:96 PS/90000\r\n");
|
||||
@ -634,11 +614,11 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
}else {
|
||||
if("TCP-PASSIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
}else if ("TCP-ACTIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
|
||||
}else if("UDP".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n");
|
||||
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n");
|
||||
}
|
||||
content.append("a=recvonly\r\n");
|
||||
content.append("a=rtpmap:96 PS/90000\r\n");
|
||||
@ -654,7 +634,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
content.append("a=downloadspeed:" + downloadSpeed + "\r\n");
|
||||
|
||||
content.append("y="+ssrc+"\r\n");//ssrc
|
||||
content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
|
||||
|
||||
String tm = Long.toString(System.currentTimeMillis());
|
||||
|
||||
@ -664,7 +644,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader);
|
||||
|
||||
ClientTransaction transaction = transmitRequest(device, request, errorEvent);
|
||||
streamSession.put(device.getDeviceId(), channelId, ssrc, streamId, transaction);
|
||||
streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), transaction);
|
||||
|
||||
} catch ( SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
@ -684,53 +664,35 @@ public class SIPCommander implements ISIPCommander {
|
||||
*/
|
||||
@Override
|
||||
public void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent) {
|
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
|
||||
try {
|
||||
ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId);
|
||||
// 服务重启后, 无法直接发送bye, 通过手动构建发送
|
||||
// if (transaction == null) {
|
||||
//
|
||||
// if (streamInfo != null) {
|
||||
// MediaServerItem mediaServerItem = redisCatchStorage.getMediaInfo(streamInfo.getMediaServerId());
|
||||
// JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaServerItem,streamInfo.getApp(), streamInfo.getStreamId());
|
||||
// if (mediaList != null) { // 仍在推流才发送
|
||||
// if (mediaList.getInteger("code") == 0) {
|
||||
// JSONArray data = mediaList.getJSONArray("data");
|
||||
// if (data != null && data.size() > 0) {
|
||||
// Device device = storager.queryVideoDevice(deviceId);
|
||||
// if (device != null) {
|
||||
// StreamInfo.TransactionInfo transactionInfo = streamInfo.getTransactionInfo();
|
||||
// try {
|
||||
// Request byteRequest = headerProvider.createByteRequest(device, channelId,
|
||||
// transactionInfo.branch,
|
||||
// transactionInfo.localTag,
|
||||
// transactionInfo.remoteTag,
|
||||
// transactionInfo.callId);
|
||||
// transmitRequest(device, byteRequest);
|
||||
// } catch (InvalidArgumentException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// redisCatchStorage.stopPlay(streamInfo);
|
||||
// }
|
||||
//
|
||||
// if (okEvent != null) {
|
||||
// okEvent.response(null);
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
if (transaction == null) {
|
||||
logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
|
||||
return;
|
||||
}
|
||||
Dialog dialog = transaction.getDialog();
|
||||
SIPDialog dialog = streamSession.getDialog(deviceId, channelId);
|
||||
if (dialog == null) {
|
||||
logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId);
|
||||
return;
|
||||
}
|
||||
SipStack sipStack = udpSipProvider.getSipStack();
|
||||
SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog);
|
||||
if (dialog != sipDialog) {
|
||||
dialog = sipDialog;
|
||||
}else {
|
||||
dialog.setSipProvider(udpSipProvider);
|
||||
try {
|
||||
Field sipStackField = SIPDialog.class.getDeclaredField("sipStack");
|
||||
sipStackField.setAccessible(true);
|
||||
sipStackField.set(dialog, sipStack);
|
||||
Field eventListenersField = SIPDialog.class.getDeclaredField("eventListeners");
|
||||
eventListenersField.setAccessible(true);
|
||||
eventListenersField.set(dialog, new HashSet<>());
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Request byeRequest = dialog.createRequest(Request.BYE);
|
||||
SipURI byeURI = (SipURI) byeRequest.getRequestURI();
|
||||
SIPRequest request = (SIPRequest)transaction.getRequest();
|
||||
@ -752,7 +714,12 @@ public class SIPCommander implements ISIPCommander {
|
||||
|
||||
dialog.sendRequest(clientTransaction);
|
||||
|
||||
SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId);
|
||||
if (ssrcTransaction != null) {
|
||||
MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
|
||||
mediaServerService.releaseSsrc(mediaServerItem, ssrcTransaction.getSsrc());
|
||||
streamSession.remove(deviceId, channelId);
|
||||
}
|
||||
} catch (SipException | ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
@ -81,7 +80,7 @@ public class AckRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
while (!rtpPushed) {
|
||||
try {
|
||||
if (System.currentTimeMillis() - startTime < 30 * 1000) {
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||
if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) {
|
||||
rtpPushed = true;
|
||||
logger.info("已获取设备推流[{}/{}],开始向上级推流[{}:{}]",
|
||||
|
@ -15,7 +15,6 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
@ -65,7 +64,7 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
param.put("stream",streamId);
|
||||
param.put("ssrc",sendRtpItem.getSsrc());
|
||||
logger.info("停止向上级推流:" + streamId);
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||
zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
|
||||
redisCatchStorage.deleteSendRTPServer(platformGbId, channelId);
|
||||
if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) {
|
||||
|
@ -11,14 +11,11 @@ import javax.sip.header.*;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
@ -97,7 +94,7 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
|
||||
// 查询平台下是否有该通道
|
||||
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
|
||||
GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
|
||||
IMediaServerItem mediaServerItem = null;
|
||||
MediaServerItem mediaServerItem = null;
|
||||
// 不是通道可能是直播流
|
||||
if (channel != null && gbStream == null ) {
|
||||
if (channel.getStatus() == 0) {
|
||||
|
@ -3,14 +3,18 @@ package com.genersoft.iot.vmp.gb28181.transmit.response.impl;
|
||||
import java.text.ParseException;
|
||||
|
||||
import javax.sip.*;
|
||||
import javax.sip.address.Address;
|
||||
import javax.sip.address.SipURI;
|
||||
import javax.sip.header.CSeqHeader;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import gov.nist.javax.sip.ResponseEventExt;
|
||||
import gov.nist.javax.sip.stack.SIPDialog;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
@ -28,6 +32,9 @@ public class InviteResponseProcessor implements ISIPResponseProcessor {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class);
|
||||
|
||||
@Autowired
|
||||
private VideoStreamSessionManager streamSession;
|
||||
|
||||
/**
|
||||
* 处理invite响应
|
||||
*
|
||||
@ -46,7 +53,7 @@ public class InviteResponseProcessor implements ISIPResponseProcessor {
|
||||
// 下发ack
|
||||
if (statusCode == Response.OK) {
|
||||
ResponseEventExt event = (ResponseEventExt)evt;
|
||||
Dialog dialog = evt.getDialog();
|
||||
SIPDialog dialog = (SIPDialog)evt.getDialog();
|
||||
CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
|
||||
Request reqAck = dialog.createAck(cseq.getSeqNumber());
|
||||
SipURI requestURI = (SipURI) reqAck.getRequestURI();
|
||||
@ -54,7 +61,12 @@ public class InviteResponseProcessor implements ISIPResponseProcessor {
|
||||
requestURI.setPort(event.getRemotePort());
|
||||
reqAck.setRequestURI(requestURI);
|
||||
logger.info("向 " + event.getRemoteIpAddress() + ":" + event.getRemotePort() + "回复ack");
|
||||
SipURI sipURI = (SipURI)dialog.getRemoteParty().getURI();
|
||||
String deviceId = requestURI.getUser();
|
||||
String channelId = sipURI.getUser();
|
||||
|
||||
dialog.sendAck(reqAck);
|
||||
|
||||
}
|
||||
} catch (InvalidArgumentException | SipException e) {
|
||||
e.printStackTrace();
|
||||
|
@ -3,15 +3,14 @@ package com.genersoft.iot.vmp.media.zlm;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetup;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.service.IPlayService;
|
||||
@ -42,7 +41,6 @@ public class ZLMHttpHookListener {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class);
|
||||
|
||||
|
||||
@Autowired
|
||||
private SIPCommander cmder;
|
||||
|
||||
@ -125,7 +123,7 @@ public class ZLMHttpHookListener {
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_play, json);
|
||||
if (subscribe != null ) {
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo != null) {
|
||||
subscribe.response(mediaInfo, json);
|
||||
}
|
||||
@ -150,7 +148,7 @@ public class ZLMHttpHookListener {
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
|
||||
if (subscribe != null) {
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo != null) {
|
||||
subscribe.response(mediaInfo, json);
|
||||
}
|
||||
@ -237,7 +235,7 @@ public class ZLMHttpHookListener {
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_shell_login, json);
|
||||
if (subscribe != null ) {
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo != null) {
|
||||
subscribe.response(mediaInfo, json);
|
||||
}
|
||||
@ -264,7 +262,7 @@ public class ZLMHttpHookListener {
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, json);
|
||||
if (subscribe != null ) {
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo != null) {
|
||||
subscribe.response(mediaInfo, json);
|
||||
}
|
||||
@ -297,7 +295,7 @@ public class ZLMHttpHookListener {
|
||||
}
|
||||
}else {
|
||||
if (!"rtp".equals(app) ){
|
||||
IMediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
if (regist) {
|
||||
zlmMediaListManager.addMedia(mediaServerItem, app, streamId);
|
||||
}else {
|
||||
@ -369,7 +367,7 @@ public class ZLMHttpHookListener {
|
||||
logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString());
|
||||
}
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (userSetup.isAutoApplyPlay() && mediaInfo != null) {
|
||||
String app = json.getString("app");
|
||||
String streamId = json.getString("stream");
|
||||
@ -381,7 +379,13 @@ public class ZLMHttpHookListener {
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
if (device != null) {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
cmder.playStreamCmd(mediaInfo, device, channelId, (IMediaServerItem mediaServerItemInuse, JSONObject response) -> {
|
||||
SSRCInfo ssrcInfo;
|
||||
String streamId2 = null;
|
||||
if (mediaInfo.isRtpEnable()) {
|
||||
streamId2 = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
|
||||
}
|
||||
ssrcInfo = mediaServerService.openRTPServer(mediaInfo, streamId2);
|
||||
cmder.playStreamCmd(mediaInfo, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
|
||||
logger.info("收到订阅消息: " + response.toJSONString());
|
||||
playService.onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid.toString());
|
||||
}, null);
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.genersoft.iot.vmp.media.zlm;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ -32,7 +31,7 @@ public class ZLMHttpHookSubscribe {
|
||||
}
|
||||
|
||||
public interface Event{
|
||||
void response(IMediaServerItem mediaServerItem, JSONObject response);
|
||||
void response(MediaServerItem mediaServerItem, JSONObject response);
|
||||
}
|
||||
|
||||
private Map<HookType, Map<JSONObject, ZLMHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
|
||||
@ -58,6 +57,9 @@ public class ZLMHttpHookSubscribe {
|
||||
if (result == null) {
|
||||
result = key.getString(s).equals(hookResponse.getString(s));
|
||||
}else {
|
||||
if (key.getString(s) == null) {
|
||||
continue;
|
||||
}
|
||||
result = result && key.getString(s).equals(hookResponse.getString(s));
|
||||
}
|
||||
|
||||
@ -83,9 +85,9 @@ public class ZLMHttpHookSubscribe {
|
||||
if (result == null) {
|
||||
result = key.getString(s).equals(hookResponse.getString(s));
|
||||
}else {
|
||||
if (key.getString(s) == null) continue;
|
||||
result = result && key.getString(s).equals(hookResponse.getString(s));
|
||||
}
|
||||
|
||||
}
|
||||
if (null != result && result){
|
||||
iterator.remove();
|
||||
|
@ -1,12 +1,9 @@
|
||||
package com.genersoft.iot.vmp.media.zlm;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||
import com.genersoft.iot.vmp.service.IStreamPushService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
@ -76,7 +73,7 @@ public class ZLMMediaListManager {
|
||||
jsonObject.put("stream", streamPushItem.getStream());
|
||||
jsonObject.put("mediaServerId", mediaServerItem.getId());
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_play,jsonObject,
|
||||
(IMediaServerItem mediaServerItemInuse, JSONObject response)->{
|
||||
(MediaServerItem mediaServerItemInuse, JSONObject response)->{
|
||||
updateMedia(mediaServerItem, response.getString("app"), response.getString("stream"));
|
||||
}
|
||||
);
|
||||
@ -86,13 +83,13 @@ public class ZLMMediaListManager {
|
||||
|
||||
}
|
||||
|
||||
public void addMedia(IMediaServerItem mediaServerItem, String app, String streamId) {
|
||||
public void addMedia(MediaServerItem mediaServerItem, String app, String streamId) {
|
||||
//使用异步更新推流
|
||||
updateMedia(mediaServerItem, app, streamId);
|
||||
}
|
||||
|
||||
|
||||
public void updateMedia(IMediaServerItem mediaServerItem, String app, String streamId) {
|
||||
public void updateMedia(MediaServerItem mediaServerItem, String app, String streamId) {
|
||||
//使用异步更新推流
|
||||
zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId, "rtmp", json->{
|
||||
|
||||
|
@ -2,14 +2,11 @@ package com.genersoft.iot.vmp.media.zlm;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import okhttp3.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.*;
|
||||
@ -27,7 +24,7 @@ public class ZLMRESTfulUtils {
|
||||
void run(JSONObject response);
|
||||
}
|
||||
|
||||
public JSONObject sendPost(IMediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
|
||||
public JSONObject sendPost(MediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
|
||||
JSONObject responseJSON = null;
|
||||
@ -93,7 +90,7 @@ public class ZLMRESTfulUtils {
|
||||
}
|
||||
|
||||
|
||||
public void sendPostForImg(IMediaServerItem mediaServerItem, String api, Map<String, Object> param, String targetPath, String fileName) {
|
||||
public void sendPostForImg(MediaServerItem mediaServerItem, String api, Map<String, Object> param, String targetPath, String fileName) {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
|
||||
JSONObject responseJSON = null;
|
||||
@ -139,7 +136,7 @@ public class ZLMRESTfulUtils {
|
||||
}
|
||||
|
||||
|
||||
public JSONObject getMediaList(IMediaServerItem mediaServerItem,String app, String stream, String schema, RequestCallback callback){
|
||||
public JSONObject getMediaList(MediaServerItem mediaServerItem, String app, String stream, String schema, RequestCallback callback){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
if (app != null) param.put("app",app);
|
||||
if (stream != null) param.put("stream",stream);
|
||||
@ -148,15 +145,15 @@ public class ZLMRESTfulUtils {
|
||||
return sendPost(mediaServerItem, "getMediaList",param, callback);
|
||||
}
|
||||
|
||||
public JSONObject getMediaList(IMediaServerItem mediaServerItem,String app, String stream){
|
||||
public JSONObject getMediaList(MediaServerItem mediaServerItem, String app, String stream){
|
||||
return getMediaList(mediaServerItem, app, stream,null, null);
|
||||
}
|
||||
|
||||
public JSONObject getMediaList(IMediaServerItem mediaServerItem,RequestCallback callback){
|
||||
public JSONObject getMediaList(MediaServerItem mediaServerItem, RequestCallback callback){
|
||||
return sendPost(mediaServerItem, "getMediaList",null, callback);
|
||||
}
|
||||
|
||||
public JSONObject getMediaInfo(IMediaServerItem mediaServerItem,String app, String schema, String stream){
|
||||
public JSONObject getMediaInfo(MediaServerItem mediaServerItem, String app, String schema, String stream){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("app",app);
|
||||
param.put("schema",schema);
|
||||
@ -165,13 +162,13 @@ public class ZLMRESTfulUtils {
|
||||
return sendPost(mediaServerItem, "getMediaInfo",param, null);
|
||||
}
|
||||
|
||||
public JSONObject getRtpInfo(IMediaServerItem mediaServerItem,String stream_id){
|
||||
public JSONObject getRtpInfo(MediaServerItem mediaServerItem, String stream_id){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("stream_id",stream_id);
|
||||
return sendPost(mediaServerItem, "getRtpInfo",param, null);
|
||||
}
|
||||
|
||||
public JSONObject addFFmpegSource(IMediaServerItem mediaServerItem,String src_url, String dst_url, String timeout_ms,
|
||||
public JSONObject addFFmpegSource(MediaServerItem mediaServerItem, String src_url, String dst_url, String timeout_ms,
|
||||
boolean enable_hls, boolean enable_mp4, String ffmpeg_cmd_key){
|
||||
logger.info(src_url);
|
||||
logger.info(dst_url);
|
||||
@ -185,41 +182,41 @@ public class ZLMRESTfulUtils {
|
||||
return sendPost(mediaServerItem, "addFFmpegSource",param, null);
|
||||
}
|
||||
|
||||
public JSONObject delFFmpegSource(IMediaServerItem mediaServerItem,String key){
|
||||
public JSONObject delFFmpegSource(MediaServerItem mediaServerItem, String key){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("key", key);
|
||||
return sendPost(mediaServerItem, "delFFmpegSource",param, null);
|
||||
}
|
||||
|
||||
public JSONObject getMediaServerConfig(IMediaServerItem mediaServerItem){
|
||||
public JSONObject getMediaServerConfig(MediaServerItem mediaServerItem){
|
||||
return sendPost(mediaServerItem, "getServerConfig",null, null);
|
||||
}
|
||||
|
||||
public JSONObject setServerConfig(IMediaServerItem mediaServerItem, Map<String, Object> param){
|
||||
public JSONObject setServerConfig(MediaServerItem mediaServerItem, Map<String, Object> param){
|
||||
return sendPost(mediaServerItem,"setServerConfig",param, null);
|
||||
}
|
||||
|
||||
public JSONObject openRtpServer(IMediaServerItem mediaServerItem,Map<String, Object> param){
|
||||
public JSONObject openRtpServer(MediaServerItem mediaServerItem, Map<String, Object> param){
|
||||
return sendPost(mediaServerItem, "openRtpServer",param, null);
|
||||
}
|
||||
|
||||
public JSONObject closeRtpServer(IMediaServerItem mediaServerItem,Map<String, Object> param) {
|
||||
public JSONObject closeRtpServer(MediaServerItem mediaServerItem, Map<String, Object> param) {
|
||||
return sendPost(mediaServerItem, "closeRtpServer",param, null);
|
||||
}
|
||||
|
||||
public JSONObject listRtpServer(IMediaServerItem mediaServerItem) {
|
||||
public JSONObject listRtpServer(MediaServerItem mediaServerItem) {
|
||||
return sendPost(mediaServerItem, "listRtpServer",null, null);
|
||||
}
|
||||
|
||||
public JSONObject startSendRtp(IMediaServerItem mediaServerItem,Map<String, Object> param) {
|
||||
public JSONObject startSendRtp(MediaServerItem mediaServerItem, Map<String, Object> param) {
|
||||
return sendPost(mediaServerItem, "startSendRtp",param, null);
|
||||
}
|
||||
|
||||
public JSONObject stopSendRtp(IMediaServerItem mediaServerItem,Map<String, Object> param) {
|
||||
public JSONObject stopSendRtp(MediaServerItem mediaServerItem, Map<String, Object> param) {
|
||||
return sendPost(mediaServerItem, "stopSendRtp",param, null);
|
||||
}
|
||||
|
||||
public JSONObject addStreamProxy(IMediaServerItem mediaServerItem,String app, String stream, String url, boolean enable_hls, boolean enable_mp4, String rtp_type) {
|
||||
public JSONObject addStreamProxy(MediaServerItem mediaServerItem, String app, String stream, String url, boolean enable_hls, boolean enable_mp4, String rtp_type) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("vhost", "__defaultVhost__");
|
||||
param.put("app", app);
|
||||
@ -231,7 +228,7 @@ public class ZLMRESTfulUtils {
|
||||
return sendPost(mediaServerItem, "addStreamProxy",param, null);
|
||||
}
|
||||
|
||||
public JSONObject closeStreams(IMediaServerItem mediaServerItem,String app, String stream) {
|
||||
public JSONObject closeStreams(MediaServerItem mediaServerItem, String app, String stream) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("vhost", "__defaultVhost__");
|
||||
param.put("app", app);
|
||||
@ -240,17 +237,17 @@ public class ZLMRESTfulUtils {
|
||||
return sendPost(mediaServerItem, "close_streams",param, null);
|
||||
}
|
||||
|
||||
public JSONObject getAllSession(IMediaServerItem mediaServerItem) {
|
||||
public JSONObject getAllSession(MediaServerItem mediaServerItem) {
|
||||
return sendPost(mediaServerItem, "getAllSession",null, null);
|
||||
}
|
||||
|
||||
public void kickSessions(IMediaServerItem mediaServerItem, String localPortSStr) {
|
||||
public void kickSessions(MediaServerItem mediaServerItem, String localPortSStr) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("local_port", localPortSStr);
|
||||
sendPost(mediaServerItem, "kick_sessions",param, null);
|
||||
}
|
||||
|
||||
public void getSnap(IMediaServerItem mediaServerItem, String flvUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
|
||||
public void getSnap(MediaServerItem mediaServerItem, String flvUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("url", flvUrl);
|
||||
param.put("timeout_sec", timeout_sec);
|
||||
|
@ -2,10 +2,7 @@ package com.genersoft.iot.vmp.media.zlm;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.gb28181.session.SsrcUtil;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -20,24 +17,16 @@ public class ZLMRTPServerFactory {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger("ZLMRTPServerFactory");
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
private int[] portRangeArray = new int[2];
|
||||
|
||||
private int currentPort = 0;
|
||||
|
||||
private Map<String, Integer> currentStreams = null;
|
||||
|
||||
public int createRTPServer(IMediaServerItem mediaServerItem, String streamId) {
|
||||
if (currentStreams == null) {
|
||||
currentStreams = new HashMap<>();
|
||||
JSONObject jsonObject = zlmresTfulUtils.listRtpServer(mediaServerItem);
|
||||
if (jsonObject != null) {
|
||||
JSONArray data = jsonObject.getJSONArray("data");
|
||||
public int createRTPServer(MediaServerItem mediaServerItem, String streamId) {
|
||||
Map<String, Integer> currentStreams = new HashMap<>();
|
||||
JSONObject listRtpServerJsonResult = zlmresTfulUtils.listRtpServer(mediaServerItem);
|
||||
if (listRtpServerJsonResult != null) {
|
||||
JSONArray data = listRtpServerJsonResult.getJSONArray("data");
|
||||
if (data != null) {
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
JSONObject dataItem = data.getJSONObject(i);
|
||||
@ -45,7 +34,6 @@ public class ZLMRTPServerFactory {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 已经在推流
|
||||
if (currentStreams.get(streamId) != null) {
|
||||
Map<String, Object> closeRtpServerParam = new HashMap<>();
|
||||
@ -56,18 +44,18 @@ public class ZLMRTPServerFactory {
|
||||
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
int result = -1;
|
||||
int newPort = getPortFromportRange();
|
||||
int newPort = getPortFromportRange(mediaServerItem);
|
||||
param.put("port", newPort);
|
||||
param.put("enable_tcp", 1);
|
||||
param.put("stream_id", streamId);
|
||||
JSONObject jsonObject = zlmresTfulUtils.openRtpServer(mediaServerItem, param);
|
||||
JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param);
|
||||
|
||||
if (jsonObject != null) {
|
||||
switch (jsonObject.getInteger("code")){
|
||||
if (openRtpServerResultJson != null) {
|
||||
switch (openRtpServerResultJson.getInteger("code")){
|
||||
case 0:
|
||||
result= newPort;
|
||||
break;
|
||||
case -300: // id已经存在, 可能已经在其他端口推流
|
||||
case -300: // id已经存在, 可能已经在其他端口推流, TODO 也可能是设备不等ack就直接推流了, 需要查询与设置的推流ip端口是否一致
|
||||
Map<String, Object> closeRtpServerParam = new HashMap<>();
|
||||
closeRtpServerParam.put("stream_id", streamId);
|
||||
zlmresTfulUtils.closeRtpServer(mediaServerItem, closeRtpServerParam);
|
||||
@ -77,7 +65,7 @@ public class ZLMRTPServerFactory {
|
||||
result= createRTPServer(mediaServerItem, streamId);
|
||||
break;
|
||||
default:
|
||||
logger.error("创建RTP Server 失败 {}: " + jsonObject.getString("msg"), newPort);
|
||||
logger.error("创建RTP Server 失败 {}: " + openRtpServerResultJson.getString("msg"), newPort);
|
||||
break;
|
||||
}
|
||||
}else {
|
||||
@ -87,7 +75,7 @@ public class ZLMRTPServerFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean closeRTPServer(IMediaServerItem serverItem, String streamId) {
|
||||
public boolean closeRTPServer(MediaServerItem serverItem, String streamId) {
|
||||
boolean result = false;
|
||||
if (serverItem !=null){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
@ -107,21 +95,25 @@ public class ZLMRTPServerFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
private int getPortFromportRange() {
|
||||
private int getPortFromportRange(MediaServerItem mediaServerItem) {
|
||||
int currentPort = mediaServerItem.getCurrentPort();
|
||||
if (currentPort == 0) {
|
||||
String[] portRangeStrArray = mediaConfig.getRtpPortRange().split(",");
|
||||
String[] portRangeStrArray = mediaServerItem.getRtpPortRange().split(",");
|
||||
portRangeArray[0] = Integer.parseInt(portRangeStrArray[0]);
|
||||
portRangeArray[1] = Integer.parseInt(portRangeStrArray[1]);
|
||||
}
|
||||
|
||||
if (currentPort == 0 || currentPort++ > portRangeArray[1]) {
|
||||
currentPort = portRangeArray[0];
|
||||
mediaServerItem.setCurrentPort(currentPort);
|
||||
return portRangeArray[0];
|
||||
} else {
|
||||
if (currentPort % 2 == 1) {
|
||||
currentPort++;
|
||||
}
|
||||
return currentPort++;
|
||||
currentPort++;
|
||||
mediaServerItem.setCurrentPort(currentPort);
|
||||
return currentPort;
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,10 +127,14 @@ public class ZLMRTPServerFactory {
|
||||
* @param tcp 是否为tcp
|
||||
* @return SendRtpItem
|
||||
*/
|
||||
public SendRtpItem createSendRtpItem(IMediaServerItem serverItem, String ip, int port, String ssrc, String platformId, String deviceId, String channelId, boolean tcp){
|
||||
String playSsrc = SsrcUtil.getPlaySsrc();
|
||||
int localPort = createRTPServer(serverItem, SsrcUtil.getPlaySsrc());
|
||||
public SendRtpItem createSendRtpItem(MediaServerItem serverItem, String ip, int port, String ssrc, String platformId, String deviceId, String channelId, boolean tcp){
|
||||
|
||||
// 使用RTPServer 功能找一个可用的端口
|
||||
String playSsrc = serverItem.getSsrcConfig().getPlaySsrc();
|
||||
int localPort = createRTPServer(serverItem, playSsrc);
|
||||
if (localPort != -1) {
|
||||
// TODO 高并发时可能因为未放入缓存而ssrc冲突
|
||||
serverItem.getSsrcConfig().releaseSsrc(playSsrc);
|
||||
closeRTPServer(serverItem, playSsrc);
|
||||
}else {
|
||||
logger.error("没有可用的端口");
|
||||
@ -168,10 +164,12 @@ public class ZLMRTPServerFactory {
|
||||
* @param tcp 是否为tcp
|
||||
* @return SendRtpItem
|
||||
*/
|
||||
public SendRtpItem createSendRtpItem(IMediaServerItem serverItem, String ip, int port, String ssrc, String platformId, String app, String stream, String channelId, boolean tcp){
|
||||
String playSsrc = SsrcUtil.getPlaySsrc();
|
||||
int localPort = createRTPServer(serverItem, SsrcUtil.getPlaySsrc());
|
||||
public SendRtpItem createSendRtpItem(MediaServerItem serverItem, String ip, int port, String ssrc, String platformId, String app, String stream, String channelId, boolean tcp){
|
||||
String playSsrc = serverItem.getSsrcConfig().getPlaySsrc();
|
||||
int localPort = createRTPServer(serverItem, playSsrc);
|
||||
if (localPort != -1) {
|
||||
// TODO 高并发时可能因为未放入缓存而ssrc冲突
|
||||
serverItem.getSsrcConfig().releaseSsrc(ssrc);
|
||||
closeRTPServer(serverItem, playSsrc);
|
||||
}else {
|
||||
logger.error("没有可用的端口");
|
||||
@ -194,7 +192,7 @@ public class ZLMRTPServerFactory {
|
||||
/**
|
||||
* 调用zlm RESTful API —— startSendRtp
|
||||
*/
|
||||
public Boolean startSendRtpStream(IMediaServerItem mediaServerItem, Map<String, Object>param) {
|
||||
public Boolean startSendRtpStream(MediaServerItem mediaServerItem, Map<String, Object>param) {
|
||||
Boolean result = false;
|
||||
JSONObject jsonObject = zlmresTfulUtils.startSendRtp(mediaServerItem, param);
|
||||
if (jsonObject == null) {
|
||||
@ -219,7 +217,7 @@ public class ZLMRTPServerFactory {
|
||||
/**
|
||||
* 查询待转推的流是否就绪
|
||||
*/
|
||||
public Boolean isStreamReady(IMediaServerItem mediaServerItem, String app, String streamId) {
|
||||
public Boolean isStreamReady(MediaServerItem mediaServerItem, String app, String streamId) {
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
|
||||
return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
|
||||
}
|
||||
@ -229,7 +227,7 @@ public class ZLMRTPServerFactory {
|
||||
* @param streamId
|
||||
* @return
|
||||
*/
|
||||
public int totalReaderCount(IMediaServerItem mediaServerItem, String app, String streamId) {
|
||||
public int totalReaderCount(MediaServerItem mediaServerItem, String app, String streamId) {
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
|
||||
return mediaInfo.getInteger("totalReaderCount");
|
||||
}
|
||||
@ -237,7 +235,7 @@ public class ZLMRTPServerFactory {
|
||||
/**
|
||||
* 调用zlm RESTful API —— stopSendRtp
|
||||
*/
|
||||
public Boolean stopSendRtpStream(IMediaServerItem mediaServerItem,Map<String, Object>param) {
|
||||
public Boolean stopSendRtpStream(MediaServerItem mediaServerItem, Map<String, Object>param) {
|
||||
Boolean result = false;
|
||||
JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param);
|
||||
if (jsonObject == null) {
|
||||
|
@ -4,22 +4,16 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.service.IStreamProxyService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.print.attribute.standard.Media;
|
||||
import java.util.*;
|
||||
|
||||
@Component
|
||||
@ -47,16 +41,26 @@ public class ZLMRunner implements CommandLineRunner {
|
||||
|
||||
@Override
|
||||
public void run(String... strings) throws Exception {
|
||||
IMediaServerItem presetMediaServer = mediaServerService.getOneByHostAndPort(
|
||||
// 清楚redis缓存的在线zlm信息
|
||||
mediaServerService.clearMediaServerForOnline();
|
||||
|
||||
// 将配置文件的meida配置写入数据库
|
||||
MediaServerItem presetMediaServer = mediaServerService.getOneByHostAndPort(
|
||||
mediaConfig.getIp(), mediaConfig.getHttpPort());
|
||||
if (presetMediaServer != null) {
|
||||
mediaConfig.setId(presetMediaServer.getId());
|
||||
mediaServerService.update(mediaConfig);
|
||||
MediaServerItem mediaSerItem = mediaConfig.getMediaSerItem();
|
||||
mediaSerItem.setId(presetMediaServer.getId());
|
||||
mediaServerService.update(mediaSerItem);
|
||||
}else {
|
||||
if (mediaConfig.getId() != null) {
|
||||
MediaServerItem mediaSerItem = mediaConfig.getMediaSerItem();
|
||||
mediaServerService.add(mediaSerItem);
|
||||
}
|
||||
}
|
||||
|
||||
// 订阅 zlm启动事件, 新的zlm也会从这里进入系统
|
||||
hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,null,
|
||||
(IMediaServerItem mediaServerItem, JSONObject response)->{
|
||||
(MediaServerItem mediaServerItem, JSONObject response)->{
|
||||
ZLMServerConfig zlmServerConfig = JSONObject.toJavaObject(response, ZLMServerConfig.class);
|
||||
if (zlmServerConfig !=null ) {
|
||||
startGetMedia.remove(zlmServerConfig.getGeneralMediaServerId());
|
||||
@ -69,23 +73,25 @@ public class ZLMRunner implements CommandLineRunner {
|
||||
logger.info("等待默认zlm接入...");
|
||||
|
||||
// 获取所有的zlm, 并开启主动连接
|
||||
List<IMediaServerItem> all = mediaServerService.getAll();
|
||||
List<MediaServerItem> all = mediaServerService.getAll();
|
||||
if (presetMediaServer == null) {
|
||||
all.add(mediaConfig.getMediaSerItem());
|
||||
}
|
||||
for (IMediaServerItem mediaServerItem : all) {
|
||||
for (MediaServerItem mediaServerItem : all) {
|
||||
if (startGetMedia == null) startGetMedia = new HashMap<>();
|
||||
startGetMedia.put(mediaServerItem.getId(), true);
|
||||
new Thread(() -> {
|
||||
ZLMServerConfig zlmServerConfig = getMediaServerConfig(mediaServerItem);
|
||||
if (zlmServerConfig != null) {
|
||||
zlmServerConfig.setIp(mediaServerItem.getIp());
|
||||
zlmServerConfig.setHttpPort(mediaServerItem.getHttpPort());
|
||||
startGetMedia.remove(mediaServerItem.getId());
|
||||
mediaServerService.handLeZLMServerConfig(zlmServerConfig);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
Timer timer = new Timer();
|
||||
// 1分钟后未连接到则不再去主动连接
|
||||
// 2分钟后未连接到则不再去主动连接, TODO 并对重启前使用此在zlm的通道发送bye
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -100,7 +106,7 @@ public class ZLMRunner implements CommandLineRunner {
|
||||
}, 60 * 1000 * 2);
|
||||
}
|
||||
|
||||
public ZLMServerConfig getMediaServerConfig(IMediaServerItem mediaServerItem) {
|
||||
public ZLMServerConfig getMediaServerConfig(MediaServerItem mediaServerItem) {
|
||||
if ( startGetMedia.get(mediaServerItem.getId()) == null || !startGetMedia.get(mediaServerItem.getId())) return null;
|
||||
JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
|
||||
ZLMServerConfig ZLMServerConfig = null;
|
||||
|
@ -1,92 +0,0 @@
|
||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
||||
|
||||
public interface IMediaServerItem {
|
||||
|
||||
String getId();
|
||||
|
||||
void setId(String id);
|
||||
|
||||
String getIp();
|
||||
|
||||
void setIp(String ip);
|
||||
|
||||
String getHookIp();
|
||||
|
||||
void setHookIp(String hookIp);
|
||||
|
||||
String getSdpIp();
|
||||
|
||||
void setSdpIp(String sdpIp);
|
||||
|
||||
String getStreamIp();
|
||||
|
||||
void setStreamIp(String streamIp);
|
||||
|
||||
int getHttpPort();
|
||||
|
||||
void setHttpPort(int httpPort);
|
||||
|
||||
int getHttpSSlPort();
|
||||
|
||||
void setHttpSSlPort(int httpSSlPort);
|
||||
|
||||
int getRtmpPort();
|
||||
|
||||
void setRtmpPort(int rtmpPort);
|
||||
|
||||
int getRtmpSSlPort();
|
||||
|
||||
void setRtmpSSlPort(int rtmpSSlPort);
|
||||
|
||||
int getRtpProxyPort();
|
||||
|
||||
void setRtpProxyPort(int rtpProxyPort);
|
||||
|
||||
int getRtspPort();
|
||||
|
||||
void setRtspPort(int rtspPort);
|
||||
|
||||
int getRtspSSLPort();
|
||||
|
||||
void setRtspSSLPort(int rtspSSLPort);
|
||||
|
||||
boolean isAutoConfig();
|
||||
|
||||
void setAutoConfig(boolean autoConfig);
|
||||
|
||||
String getSecret();
|
||||
|
||||
void setSecret(String secret);
|
||||
|
||||
String getStreamNoneReaderDelayMS();
|
||||
|
||||
void setStreamNoneReaderDelayMS(String streamNoneReaderDelayMS);
|
||||
|
||||
boolean isRtpEnable();
|
||||
|
||||
void setRtpEnable(boolean rtpEnable);
|
||||
|
||||
String getRtpPortRange();
|
||||
|
||||
void setRtpPortRange(String rtpPortRange);
|
||||
|
||||
int getRecordAssistPort();
|
||||
|
||||
void setRecordAssistPort(int recordAssistPort);
|
||||
|
||||
boolean isDocker();
|
||||
|
||||
void setDocker(boolean docker);
|
||||
|
||||
String getUpdateTime();
|
||||
|
||||
void setUpdateTime(String updateTime);
|
||||
|
||||
String getCreateTime();
|
||||
|
||||
void setCreateTime(String createTime);
|
||||
|
||||
int getCount();
|
||||
|
||||
void setCount(int count);
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
||||
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class MediaServerItem implements IMediaServerItem{
|
||||
import java.util.HashMap;
|
||||
|
||||
public class MediaServerItem{
|
||||
|
||||
private String id;
|
||||
|
||||
@ -46,9 +49,18 @@ public class MediaServerItem implements IMediaServerItem{
|
||||
|
||||
private String updateTime;
|
||||
|
||||
private boolean docker;
|
||||
private boolean defaultServer;
|
||||
|
||||
private int count;
|
||||
private SsrcConfig ssrcConfig;
|
||||
|
||||
private int currentPort;
|
||||
|
||||
|
||||
/**
|
||||
* 每一台ZLM都有一套独立的SSRC列表
|
||||
* 在ApplicationCheckRunner里对mediaServerSsrcMap进行初始化
|
||||
*/
|
||||
private HashMap<String, SsrcConfig> mediaServerSsrcMap;
|
||||
|
||||
public MediaServerItem() {
|
||||
}
|
||||
@ -218,14 +230,12 @@ public class MediaServerItem implements IMediaServerItem{
|
||||
this.recordAssistPort = recordAssistPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDocker() {
|
||||
return docker;
|
||||
public boolean isDefaultServer() {
|
||||
return defaultServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDocker(boolean docker) {
|
||||
this.docker = docker;
|
||||
public void setDefaultServer(boolean defaultServer) {
|
||||
this.defaultServer = defaultServer;
|
||||
}
|
||||
|
||||
public String getCreateTime() {
|
||||
@ -244,11 +254,29 @@ public class MediaServerItem implements IMediaServerItem{
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
public HashMap<String, SsrcConfig> getMediaServerSsrcMap() {
|
||||
return mediaServerSsrcMap;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
public void setMediaServerSsrcMap(HashMap<String, SsrcConfig> mediaServerSsrcMap) {
|
||||
this.mediaServerSsrcMap = mediaServerSsrcMap;
|
||||
}
|
||||
|
||||
public SsrcConfig getSsrcConfig() {
|
||||
return ssrcConfig;
|
||||
}
|
||||
|
||||
public void setSsrcConfig(SsrcConfig ssrcConfig) {
|
||||
this.ssrcConfig = ssrcConfig;
|
||||
}
|
||||
|
||||
public int getCurrentPort() {
|
||||
return currentPort;
|
||||
}
|
||||
|
||||
public void setCurrentPort(int currentPort) {
|
||||
this.currentPort = currentPort;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package com.genersoft.iot.vmp.service;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -13,11 +13,13 @@ import java.util.List;
|
||||
*/
|
||||
public interface IMediaServerService {
|
||||
|
||||
List<IMediaServerItem> getAll();
|
||||
List<MediaServerItem> getAll();
|
||||
|
||||
IMediaServerItem getOne(String generalMediaServerId);
|
||||
List<MediaServerItem> getAllOnline();
|
||||
|
||||
IMediaServerItem getOneByHostAndPort(String host, int port);
|
||||
MediaServerItem getOne(String generalMediaServerId);
|
||||
|
||||
MediaServerItem getOneByHostAndPort(String host, int port);
|
||||
|
||||
/**
|
||||
* 新的节点加入
|
||||
@ -26,19 +28,27 @@ public interface IMediaServerService {
|
||||
*/
|
||||
void handLeZLMServerConfig(ZLMServerConfig zlmServerConfig);
|
||||
|
||||
void updateServerCatch(IMediaServerItem mediaServerItem, Integer count, Boolean b);
|
||||
MediaServerItem getMediaServerForMinimumLoad();
|
||||
|
||||
IMediaServerItem getMediaServerForMinimumLoad();
|
||||
void setZLMConfig(MediaServerItem mediaServerItem);
|
||||
|
||||
void setZLMConfig(IMediaServerItem mediaServerItem);
|
||||
|
||||
void init();
|
||||
SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId);
|
||||
|
||||
void closeRTPServer(Device device, String channelId);
|
||||
|
||||
void update(MediaConfig mediaConfig);
|
||||
void clearRTPServer(MediaServerItem mediaServerItem);
|
||||
|
||||
void update(MediaServerItem mediaSerItem);
|
||||
|
||||
void addCount(String mediaServerId);
|
||||
|
||||
void removeCount(String mediaServerId);
|
||||
|
||||
void releaseSsrc(MediaServerItem mediaServerItem, String ssrc);
|
||||
|
||||
void clearMediaServerForOnline();
|
||||
|
||||
void add(MediaServerItem mediaSerItem);
|
||||
|
||||
void resetOnlineServerItem(MediaServerItem serverItem);
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
|
||||
/**
|
||||
@ -33,7 +32,7 @@ public interface IMediaService {
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaServerItem, String app, String stream, JSONArray tracks);
|
||||
StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaServerItem, String app, String stream, JSONArray tracks);
|
||||
|
||||
/**
|
||||
* 根据应用名和流ID获取播放地址, 只是地址拼接,返回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
|
||||
@ -41,5 +40,5 @@ public interface IMediaService {
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks, String addr);
|
||||
StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, JSONArray tracks, String addr);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
|
||||
|
||||
@ -13,10 +12,10 @@ import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
|
||||
*/
|
||||
public interface IPlayService {
|
||||
|
||||
void onPublishHandlerForPlayBack(IMediaServerItem mediaServerItem,JSONObject resonse, String deviceId, String channelId, String uuid);
|
||||
void onPublishHandlerForPlay(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid);
|
||||
void onPublishHandlerForPlayBack(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid);
|
||||
void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid);
|
||||
|
||||
PlayResult play(IMediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
||||
|
||||
IMediaServerItem getNewMediaServerItem(Device device);
|
||||
MediaServerItem getNewMediaServerItem(Device device);
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
@ -63,5 +62,5 @@ public interface IStreamProxyService {
|
||||
* 获取ffmpeg.cmd模板
|
||||
* @return
|
||||
*/
|
||||
JSONObject getFFmpegCMDs(IMediaServerItem mediaServerItem);
|
||||
JSONObject getFFmpegCMDs(MediaServerItem mediaServerItem);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
|
||||
@ -9,7 +9,7 @@ import java.util.List;
|
||||
|
||||
public interface IStreamPushService {
|
||||
|
||||
List<StreamPushItem> handleJSON(String json, IMediaServerItem mediaServerItem);
|
||||
List<StreamPushItem> handleJSON(String json, MediaServerItem mediaServerItem);
|
||||
|
||||
/**
|
||||
* 将应用名和流ID加入国标关联
|
||||
|
@ -0,0 +1,38 @@
|
||||
package com.genersoft.iot.vmp.service.bean;
|
||||
|
||||
public class SSRCInfo {
|
||||
|
||||
private int port;
|
||||
private String ssrc;
|
||||
private String StreamId;
|
||||
|
||||
public SSRCInfo(int port, String ssrc, String streamId) {
|
||||
this.port = port;
|
||||
this.ssrc = ssrc;
|
||||
StreamId = streamId;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getSsrc() {
|
||||
return ssrc;
|
||||
}
|
||||
|
||||
public void setSsrc(String ssrc) {
|
||||
this.ssrc = ssrc;
|
||||
}
|
||||
|
||||
public String getStreamId() {
|
||||
return StreamId;
|
||||
}
|
||||
|
||||
public void setStreamId(String streamId) {
|
||||
StreamId = streamId;
|
||||
}
|
||||
}
|
@ -1,29 +1,32 @@
|
||||
package com.genersoft.iot.vmp.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.conf.ProxyServletConfig;
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.ZLMRunInfo;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.dao.MediaServerMapper;
|
||||
import org.mitre.dsmiley.httpproxy.ProxyServlet;
|
||||
import com.genersoft.iot.vmp.utils.redis.JedisUtil;
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
@ -31,15 +34,13 @@ import java.util.*;
|
||||
* 媒体服务器节点管理
|
||||
*/
|
||||
@Service
|
||||
public class MediaServerServiceImpl implements IMediaServerService {
|
||||
@Order(value=2)
|
||||
public class MediaServerServiceImpl implements IMediaServerService, CommandLineRunner {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(MediaServerServiceImpl.class);
|
||||
|
||||
private Map<String, IMediaServerItem> zlmServers = new HashMap<>(); // 所有数据库的zlm的缓存
|
||||
private Map<String, Integer> zlmServerStatus = new LinkedHashMap<>(); // 所有上线的zlm的缓存以及负载
|
||||
|
||||
@Value("${sip.ip}")
|
||||
private String sipIp;
|
||||
@Autowired
|
||||
private SipConfig sipConfig;
|
||||
|
||||
@Value("${server.ssl.enabled:false}")
|
||||
private boolean sslEnabled;
|
||||
@ -56,7 +57,6 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
@Autowired
|
||||
private MediaServerMapper mediaServerMapper;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@ -66,53 +66,134 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
@Autowired
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@Autowired
|
||||
JedisUtil jedisUtil;
|
||||
|
||||
private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
@Override
|
||||
public void init() {
|
||||
zlmServers.clear();
|
||||
zlmServerStatus.clear();
|
||||
public void run(String... args) throws Exception {
|
||||
logger.info("Media Server 缓存初始化");
|
||||
List<MediaServerItem> mediaServerItemList = mediaServerMapper.queryAll();
|
||||
for (IMediaServerItem mediaServerItem : mediaServerItemList) {
|
||||
zlmServers.put(mediaServerItem.getId(), mediaServerItem);
|
||||
for (MediaServerItem mediaServerItem : mediaServerItemList) {
|
||||
// 更新
|
||||
if (mediaServerItem.getSsrcConfig() == null) {
|
||||
SsrcConfig ssrcConfig = new SsrcConfig(mediaServerItem.getId(), null, sipConfig.getSipDomain());
|
||||
mediaServerItem.setSsrcConfig(ssrcConfig);
|
||||
redisUtil.set(VideoManagerConstants.MEDIA_SERVER_PREFIX + mediaServerItem.getId(), mediaServerItem);
|
||||
}
|
||||
// 查询redis是否存在此mediaServer
|
||||
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + mediaServerItem.getId();
|
||||
if (!redisUtil.hasKey(key)) {
|
||||
redisUtil.set(key, mediaServerItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId) {
|
||||
if (mediaServerItem == null || mediaServerItem.getId() == null) return null;
|
||||
// 获取mediaServer可用的ssrc
|
||||
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + mediaServerItem.getId();
|
||||
|
||||
SsrcConfig ssrcConfig = mediaServerItem.getSsrcConfig();
|
||||
if (ssrcConfig == null) {
|
||||
logger.info("media server [ {} ] ssrcConfig is null", mediaServerItem.getId());
|
||||
return null;
|
||||
}else {
|
||||
String ssrc = ssrcConfig.getPlaySsrc();
|
||||
if (streamId == null) streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
|
||||
int rtpServerPort = mediaServerItem.getRtpProxyPort();
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId);
|
||||
}
|
||||
redisUtil.set(key, mediaServerItem);
|
||||
return new SSRCInfo(rtpServerPort, ssrc, streamId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeRTPServer(Device device, String channelId) {
|
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
|
||||
IMediaServerItem mediaServerItem = null;
|
||||
if (streamInfo != null) {
|
||||
mediaServerItem = this.getOne (streamInfo.getMediaServerId());
|
||||
}
|
||||
String mediaServerId = streamSession.getMediaServerId(device.getDeviceId(), channelId);
|
||||
MediaServerItem mediaServerItem = this.getOne(mediaServerId);
|
||||
if (mediaServerItem != null) {
|
||||
String streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
|
||||
zlmrtpServerFactory.closeRTPServer(mediaServerItem, streamId);
|
||||
releaseSsrc(mediaServerItem, streamSession.getSSRC(device.getDeviceId(), channelId));
|
||||
}
|
||||
streamSession.remove(device.getDeviceId(), channelId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(MediaConfig mediaConfig) {
|
||||
public void releaseSsrc(MediaServerItem mediaServerItem, String ssrc) {
|
||||
if (mediaServerItem == null || ssrc == null) return;
|
||||
SsrcConfig ssrcConfig = mediaServerItem.getSsrcConfig();
|
||||
ssrcConfig.releaseSsrc(ssrc);
|
||||
mediaServerItem.setSsrcConfig(ssrcConfig);
|
||||
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + mediaServerItem.getId();
|
||||
redisUtil.set(key, mediaServerItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* zlm 重启后重置他的推流信息, TODO 给正在使用的设备发送停止命令
|
||||
* @param mediaServerItem
|
||||
*/
|
||||
@Override
|
||||
public void clearRTPServer(MediaServerItem mediaServerItem) {
|
||||
mediaServerItem.setSsrcConfig(new SsrcConfig(mediaServerItem.getId(), null, sipConfig.getSipDomain()));
|
||||
redisUtil.zAdd(VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX, mediaServerItem.getId(), 0);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update(MediaServerItem mediaSerItem) {
|
||||
mediaServerMapper.update(mediaSerItem);
|
||||
MediaServerItem mediaServerItemInRedis = getOne(mediaSerItem.getId());
|
||||
MediaServerItem mediaServerItemInDataBase = mediaServerMapper.queryOne(mediaSerItem.getId());
|
||||
if (mediaServerItemInRedis != null && mediaServerItemInRedis.getSsrcConfig() != null) {
|
||||
mediaServerItemInDataBase.setSsrcConfig(mediaServerItemInRedis.getSsrcConfig());
|
||||
}else {
|
||||
mediaServerItemInDataBase.setSsrcConfig(
|
||||
new SsrcConfig(
|
||||
mediaServerItemInDataBase.getId(),
|
||||
null,
|
||||
sipConfig.getSipDomain()
|
||||
)
|
||||
);
|
||||
}
|
||||
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + mediaServerItemInDataBase.getId();
|
||||
redisUtil.set(key, mediaServerItemInDataBase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IMediaServerItem> getAll() {
|
||||
if (zlmServers.size() == 0) {
|
||||
init();
|
||||
}
|
||||
List<IMediaServerItem> result = new ArrayList<>();
|
||||
for (String id : zlmServers.keySet()) {
|
||||
IMediaServerItem mediaServerItem = zlmServers.get(id);
|
||||
mediaServerItem.setCount(zlmServerStatus.get(id) == null ? 0 : zlmServerStatus.get(id));
|
||||
result.add(mediaServerItem);
|
||||
public List<MediaServerItem> getAll() {
|
||||
List<MediaServerItem> result = new ArrayList<>();
|
||||
List<Object> mediaServerKeys = redisUtil.scan(String.format("%S*", VideoManagerConstants.MEDIA_SERVER_PREFIX));
|
||||
for (int i = 0; i < mediaServerKeys.size(); i++) {
|
||||
String key = (String) mediaServerKeys.get(i);
|
||||
result.add((MediaServerItem)redisUtil.get(key));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// return mediaServerMapper.queryAll();
|
||||
@Override
|
||||
public List<MediaServerItem> getAllOnline() {
|
||||
String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX;
|
||||
Set<String> mediaServerIdSet = redisUtil.zRevRange(key, 0, -1);
|
||||
List<MediaServerItem> result = new ArrayList<>();
|
||||
if (mediaServerIdSet != null && mediaServerIdSet.size() > 0) {
|
||||
for (String mediaServerId : mediaServerIdSet) {
|
||||
String serverKey = VideoManagerConstants.MEDIA_SERVER_PREFIX + mediaServerId;
|
||||
result.add((MediaServerItem) redisUtil.get(serverKey));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -121,26 +202,28 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
* @return MediaServerItem
|
||||
*/
|
||||
@Override
|
||||
public IMediaServerItem getOne(String mediaServerId) {
|
||||
public MediaServerItem getOne(String mediaServerId) {
|
||||
if (mediaServerId == null) return null;
|
||||
IMediaServerItem mediaServerItem = zlmServers.get(mediaServerId);
|
||||
if (mediaServerItem != null) {
|
||||
mediaServerItem.setCount(zlmServerStatus.get(mediaServerId) == null ? 0 : zlmServerStatus.get(mediaServerId));
|
||||
return mediaServerItem;
|
||||
}else {
|
||||
IMediaServerItem item = mediaServerMapper.queryOne(mediaServerId);
|
||||
if (item != null) {
|
||||
zlmServers.put(item.getId(), item);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + mediaServerId;
|
||||
return (MediaServerItem)redisUtil.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMediaServerItem getOneByHostAndPort(String host, int port) {
|
||||
public MediaServerItem getOneByHostAndPort(String host, int port) {
|
||||
return mediaServerMapper.queryOneByHostAndPort(host, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearMediaServerForOnline() {
|
||||
String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX;
|
||||
redisUtil.del(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(MediaServerItem mediaSerItem) {
|
||||
mediaServerMapper.add(mediaSerItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理zlm上线
|
||||
* @param zlmServerConfig zlm上线携带的参数
|
||||
@ -150,111 +233,100 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
logger.info("[ {} ]-[ {}:{} ]已连接",
|
||||
zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
|
||||
|
||||
IMediaServerItem serverItem = getOne(zlmServerConfig.getGeneralMediaServerId());
|
||||
String now = this.format.format(new Date(System.currentTimeMillis()));
|
||||
if (serverItem != null) {
|
||||
serverItem.setSecret(zlmServerConfig.getApiSecret());
|
||||
serverItem.setIp(zlmServerConfig.getIp());
|
||||
// 如果是配置文件中的zlm。 也就是默认zlm。 一切以配置文件内容为准
|
||||
// docker部署不会使用zlm配置的端口号;
|
||||
// 直接编译部署的使用配置文件的端口号,如果zlm修改配改了配置,wvp自动修改
|
||||
|
||||
if (serverItem.getId().equals(mediaConfig.getId())
|
||||
|| (serverItem.getIp().equals(mediaConfig.getIp()) && serverItem.getHttpPort() == mediaConfig.getHttpPort())) {
|
||||
// 配置文件的zlm
|
||||
mediaConfig.setId(zlmServerConfig.getGeneralMediaServerId());
|
||||
mediaConfig.setUpdateTime(now);
|
||||
if (mediaConfig.getHttpPort() == 0) mediaConfig.setHttpPort(zlmServerConfig.getHttpPort());
|
||||
if (mediaConfig.getHttpSSlPort() == 0) mediaConfig.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
|
||||
if (mediaConfig.getRtmpPort() == 0) mediaConfig.setRtmpPort(zlmServerConfig.getRtmpPort());
|
||||
if (mediaConfig.getRtmpSSlPort() == 0) mediaConfig.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
|
||||
if (mediaConfig.getRtspPort() == 0) mediaConfig.setRtspPort(zlmServerConfig.getRtspPort());
|
||||
if (mediaConfig.getRtspSSLPort() == 0) mediaConfig.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
|
||||
if (mediaConfig.getRtpProxyPort() == 0) mediaConfig.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
|
||||
mediaServerMapper.update(mediaConfig);
|
||||
serverItem = mediaConfig.getMediaSerItem();
|
||||
setZLMConfig(mediaConfig);
|
||||
}else {
|
||||
if (!serverItem.isDocker()) {
|
||||
serverItem.setHttpPort(zlmServerConfig.getHttpPort());
|
||||
serverItem.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
|
||||
serverItem.setRtmpPort(zlmServerConfig.getRtmpPort());
|
||||
serverItem.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
|
||||
serverItem.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
|
||||
serverItem.setRtspPort(zlmServerConfig.getRtspPort());
|
||||
|
||||
MediaServerItem serverItem = mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId());
|
||||
if (serverItem == null) {
|
||||
serverItem = mediaServerMapper.queryOneByHostAndPort(zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
|
||||
}
|
||||
serverItem.setUpdateTime(now);
|
||||
mediaServerMapper.update(serverItem);
|
||||
setZLMConfig(serverItem);
|
||||
}
|
||||
}else {
|
||||
if (zlmServerConfig.getGeneralMediaServerId().equals(mediaConfig.getId())
|
||||
|| (zlmServerConfig.getIp().equals(mediaConfig.getIp()) && zlmServerConfig.getHttpPort() == mediaConfig.getHttpPort())) {
|
||||
mediaConfig.setId(zlmServerConfig.getGeneralMediaServerId());
|
||||
mediaConfig.setCreateTime(now);
|
||||
mediaConfig.setUpdateTime(now);
|
||||
serverItem = mediaConfig.getMediaSerItem();
|
||||
mediaServerMapper.add(mediaConfig);
|
||||
// 配置文件的zlm
|
||||
// 如果是配置文件中的zlm。 也就是默认zlm。 一切以配置文件内容为准
|
||||
// docker部署不会使用zlm配置的端口号不是默认的则不做更新, 配置修改需要自行修改server配置;
|
||||
MediaServerItem serverItemFromConfig = mediaConfig.getMediaSerItem();
|
||||
serverItemFromConfig.setId(zlmServerConfig.getGeneralMediaServerId());
|
||||
if (mediaConfig.getHttpPort() == 0) serverItemFromConfig.setHttpPort(zlmServerConfig.getHttpPort());
|
||||
if (mediaConfig.getHttpSSlPort() == 0) serverItemFromConfig.setHttpSSlPort(zlmServerConfig.getHttpSSLport());
|
||||
if (mediaConfig.getRtmpPort() == 0) serverItemFromConfig.setRtmpPort(zlmServerConfig.getRtmpPort());
|
||||
if (mediaConfig.getRtmpSSlPort() == 0) serverItemFromConfig.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
|
||||
if (mediaConfig.getRtspPort() == 0) serverItemFromConfig.setRtspPort(zlmServerConfig.getRtspPort());
|
||||
if (mediaConfig.getRtspSSLPort() == 0) serverItemFromConfig.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
|
||||
if (mediaConfig.getRtpProxyPort() == 0) serverItemFromConfig.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
|
||||
if (serverItem != null){
|
||||
// 可能是同一个zlm但id发生了变化
|
||||
if (!serverItem.getId().equals(zlmServerConfig.getGeneralMediaServerId())) {
|
||||
mediaServerMapper.delOne(serverItem.getId());
|
||||
redisUtil.del(VideoManagerConstants.MEDIA_SERVER_PREFIX + serverItem.getId());
|
||||
|
||||
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + serverItemFromConfig.getId();
|
||||
serverItemFromConfig.setSsrcConfig(new SsrcConfig(serverItemFromConfig.getId(), null, sipConfig.getSipDomain()));
|
||||
redisUtil.set(key, serverItemFromConfig);
|
||||
mediaServerMapper.add(serverItemFromConfig);
|
||||
}else {
|
||||
mediaServerMapper.update(serverItemFromConfig);
|
||||
}
|
||||
}else {
|
||||
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + serverItemFromConfig.getId();
|
||||
serverItemFromConfig.setSsrcConfig(new SsrcConfig(serverItemFromConfig.getId(), null, sipConfig.getSipDomain()));
|
||||
redisUtil.set(key, serverItemFromConfig);
|
||||
mediaServerMapper.add(serverItemFromConfig);
|
||||
}
|
||||
resetOnlineServerItem(serverItemFromConfig);
|
||||
setZLMConfig(serverItemFromConfig);
|
||||
}else {
|
||||
String now = this.format.format(new Date(System.currentTimeMillis()));
|
||||
if (serverItem == null){
|
||||
// 一个新的zlm接入wvp
|
||||
serverItem = new MediaServerItem(zlmServerConfig, sipIp);
|
||||
serverItem = new MediaServerItem(zlmServerConfig, sipConfig.getSipIp());
|
||||
serverItem.setCreateTime(now);
|
||||
serverItem.setUpdateTime(now);
|
||||
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + serverItem.getId();
|
||||
serverItem.setSsrcConfig(new SsrcConfig(serverItem.getId(), null, sipConfig.getSipDomain()));
|
||||
redisUtil.set(key, serverItem);
|
||||
// 存入数据库
|
||||
mediaServerMapper.add(serverItem);
|
||||
setZLMConfig(serverItem);
|
||||
}
|
||||
resetOnlineServerItem(serverItem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetOnlineServerItem(MediaServerItem serverItem) {
|
||||
// 更新缓存
|
||||
if (zlmServerStatus.get(serverItem.getId()) == null) {
|
||||
zlmServers.put(serverItem.getId(), serverItem);
|
||||
zlmServerStatus.put(serverItem.getId(),0);
|
||||
}
|
||||
String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX;
|
||||
// 使用zset的分数作为当前并发量, 默认值设置为0
|
||||
if (redisUtil.zScore(key, serverItem.getId()) == null) { // 不存在则设置默认值 已存在则重置
|
||||
redisUtil.zAdd(key, serverItem.getId(), 0L);
|
||||
// 查询服务流数量
|
||||
IMediaServerItem finalServerItem = serverItem;
|
||||
zlmresTfulUtils.getMediaList(serverItem, null, null, "rtmp",(mediaList ->{
|
||||
Integer code = mediaList.getInteger("code");
|
||||
if (code == 0) {
|
||||
JSONArray data = mediaList.getJSONArray("data");
|
||||
if (data != null) {
|
||||
zlmServerStatus.put(finalServerItem.getId(),data.size());
|
||||
}else {
|
||||
zlmServerStatus.put(finalServerItem.getId(),0);
|
||||
redisUtil.zAdd(key, serverItem.getId(), data.size());
|
||||
}
|
||||
|
||||
}
|
||||
}));
|
||||
}else {
|
||||
clearRTPServer(serverItem);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新缓存
|
||||
* @param mediaServerItem zlm服务
|
||||
* @param count 在线数
|
||||
* @param online 在线状态
|
||||
*/
|
||||
@Override
|
||||
public void updateServerCatch(IMediaServerItem mediaServerItem, Integer count, Boolean online) {
|
||||
if (mediaServerItem != null) {
|
||||
zlmServers.put(mediaServerItem.getId(), mediaServerItem);
|
||||
Collection<Integer> values = zlmServerStatus.values();
|
||||
if (online != null && count != null) {
|
||||
zlmServerStatus.put(mediaServerItem.getId(), count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCount(String mediaServerId) {
|
||||
if (zlmServerStatus.get(mediaServerId) != null) {
|
||||
zlmServerStatus.put(mediaServerId, zlmServerStatus.get(mediaServerId) + 1);
|
||||
}
|
||||
if (mediaServerId == null) return;
|
||||
String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX;
|
||||
Double aDouble = redisUtil.zScore(key, mediaServerId);
|
||||
redisUtil.zIncrScore(key, mediaServerId, 1);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCount(String mediaServerId) {
|
||||
if (zlmServerStatus.get(mediaServerId) != null) {
|
||||
zlmServerStatus.put(mediaServerId, zlmServerStatus.get(mediaServerId) - 1);
|
||||
}
|
||||
String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX;
|
||||
redisUtil.zIncrScore(key, mediaServerId, - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,35 +334,18 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
* @return MediaServerItem
|
||||
*/
|
||||
@Override
|
||||
public IMediaServerItem getMediaServerForMinimumLoad() {
|
||||
int mediaCount = -1;
|
||||
String key = null;
|
||||
System.out.println(JSON.toJSONString(zlmServerStatus));
|
||||
if (zlmServerStatus.size() == 1) {
|
||||
Map.Entry entry = zlmServerStatus.entrySet().iterator().next();
|
||||
key= (String) entry.getKey();
|
||||
}else {
|
||||
for (String id : zlmServerStatus.keySet()) {
|
||||
if (key == null) {
|
||||
key = id;
|
||||
mediaCount = zlmServerStatus.get(id);
|
||||
}
|
||||
if (zlmServerStatus.get(id) == 0) {
|
||||
key = id;
|
||||
break;
|
||||
}else if (mediaCount >= zlmServerStatus.get(id)){
|
||||
mediaCount = zlmServerStatus.get(id);
|
||||
key = id;
|
||||
}
|
||||
}
|
||||
public MediaServerItem getMediaServerForMinimumLoad() {
|
||||
String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX;
|
||||
|
||||
if (redisUtil.zSize(key) == null || redisUtil.zSize(key) == 0) {
|
||||
logger.info("获取负载最低的节点时无在线节点");
|
||||
}
|
||||
|
||||
if (key == null) {
|
||||
logger.info("获取负载最低的节点时无在线节点");
|
||||
return null;
|
||||
}else{
|
||||
return zlmServers.get(key);
|
||||
}
|
||||
// 获取分数最低的,及并发最低的
|
||||
Set<Object> objects = redisUtil.ZRange(key, 0, -1);
|
||||
ArrayList<Object> MediaServerObjectS = new ArrayList<>(objects);
|
||||
String mediaServerId = (String)MediaServerObjectS.get(0);
|
||||
return getOne(mediaServerId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -298,7 +353,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
* @param mediaServerItem 服务ID
|
||||
*/
|
||||
@Override
|
||||
public void setZLMConfig(IMediaServerItem mediaServerItem) {
|
||||
public void setZLMConfig(MediaServerItem mediaServerItem) {
|
||||
logger.info("[ {} ]-[ {}:{} ]设置zlm",
|
||||
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||
String protocol = sslEnabled ? "https" : "http";
|
||||
@ -333,8 +388,10 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
logger.info("[ {} ]-[ {}:{} ]设置zlm成功",
|
||||
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||
}else {
|
||||
logger.info("[ {} ]-[ {}:{} ]设置zlm失败" + responseJSON.getString("msg"),
|
||||
logger.info("[ {} ]-[ {}:{} ]设置zlm失败",
|
||||
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -4,9 +4,7 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
@ -33,14 +31,14 @@ public class MediaServiceImpl implements IMediaService {
|
||||
|
||||
|
||||
@Override
|
||||
public StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks) {
|
||||
public StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, JSONArray tracks) {
|
||||
return getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, String addr) {
|
||||
StreamInfo streamInfo = null;
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo == null) {
|
||||
return streamInfo;
|
||||
}
|
||||
@ -63,7 +61,7 @@ public class MediaServiceImpl implements IMediaService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamInfo getStreamInfoByAppAndStream(IMediaServerItem mediaInfo, String app, String stream, JSONArray tracks, String addr) {
|
||||
public StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, JSONArray tracks, String addr) {
|
||||
StreamInfo streamInfoResult = new StreamInfo();
|
||||
streamInfoResult.setStreamId(stream);
|
||||
streamInfoResult.setApp(app);
|
||||
|
@ -14,11 +14,12 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
|
||||
import com.genersoft.iot.vmp.service.IMediaService;
|
||||
@ -53,6 +54,9 @@ public class PlayServiceImpl implements IPlayService {
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redis;
|
||||
|
||||
@Autowired
|
||||
private DeferredResultHolder resultHolder;
|
||||
|
||||
@ -73,7 +77,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
|
||||
|
||||
@Override
|
||||
public PlayResult play(IMediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
|
||||
public PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
|
||||
PlayResult playResult = new PlayResult();
|
||||
if (mediaServerItem == null) {
|
||||
RequestMessage msg = new RequestMessage();
|
||||
@ -97,14 +101,21 @@ public class PlayServiceImpl implements IPlayService {
|
||||
// 超时处理
|
||||
result.onTimeout(()->{
|
||||
logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
|
||||
// 释放rtpserver
|
||||
mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + playResult.getUuid());
|
||||
WVPResult wvpResult = new WVPResult();
|
||||
wvpResult.setCode(-1);
|
||||
wvpResult.setMsg("Timeout");
|
||||
SIPDialog dialog = streamSession.getDialog(deviceId, channelId);
|
||||
if (dialog != null) {
|
||||
wvpResult.setMsg("收流超时,请稍候重试");
|
||||
}else {
|
||||
wvpResult.setMsg("点播超时,请稍候重试");
|
||||
}
|
||||
msg.setData(wvpResult);
|
||||
// 点播超时回复BYE
|
||||
cmder.streamByeCmd(device.getDeviceId(), channelId);
|
||||
// 释放rtpserver
|
||||
mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
result.onCompletion(()->{
|
||||
@ -131,7 +142,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
WVPResult wvpResult = (WVPResult)responseEntity.getBody();
|
||||
if (wvpResult.getCode() == 0) {
|
||||
StreamInfo streamInfoForSuccess = (StreamInfo)wvpResult.getData();
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId());
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId());
|
||||
String streamUrl = streamInfoForSuccess.getFmp4();
|
||||
// 请求截图
|
||||
zlmresTfulUtils.getSnap(mediaInfo, streamUrl, 15, 1, path, fileName);
|
||||
@ -142,14 +153,23 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
});
|
||||
if (streamInfo == null) {
|
||||
SSRCInfo ssrcInfo;
|
||||
String streamId = null;
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
|
||||
}
|
||||
|
||||
ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId);
|
||||
|
||||
// 发送点播消息
|
||||
cmder.playStreamCmd(mediaServerItem, device, channelId, (IMediaServerItem mediaServerItemInUse, JSONObject response) -> {
|
||||
cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
|
||||
logger.info("收到订阅消息: " + response.toJSONString());
|
||||
onPublishHandlerForPlay(mediaServerItemInUse, response, deviceId, channelId, uuid.toString());
|
||||
if (hookEvent != null) {
|
||||
hookEvent.response(mediaServerItem, response);
|
||||
}
|
||||
}, (event) -> {
|
||||
// 点播返回sip错误
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
|
||||
Response response = event.getResponse();
|
||||
@ -162,6 +182,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
if (errorEvent != null) {
|
||||
errorEvent.response(event);
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
String streamId = streamInfo.getStreamId();
|
||||
@ -176,7 +197,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
return playResult;
|
||||
}
|
||||
String mediaServerId = streamInfo.getMediaServerId();
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
|
||||
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
|
||||
if (rtpInfo != null && rtpInfo.getBoolean("exist")) {
|
||||
@ -194,9 +215,17 @@ public class PlayServiceImpl implements IPlayService {
|
||||
hookEvent.response(mediaServerItem, JSONObject.parseObject(JSON.toJSONString(streamInfo)));
|
||||
}
|
||||
} else {
|
||||
// TODO 点播前是否重置状态
|
||||
redisCatchStorage.stopPlay(streamInfo);
|
||||
storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
|
||||
cmder.playStreamCmd(mediaServerItem, device, channelId, (IMediaServerItem mediaServerItemInuse, JSONObject response) -> {
|
||||
SSRCInfo ssrcInfo;
|
||||
String streamId2 = null;
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
streamId2 = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
|
||||
}
|
||||
ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId2);
|
||||
|
||||
cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
|
||||
logger.info("收到订阅消息: " + response.toJSONString());
|
||||
onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid.toString());
|
||||
}, (event) -> {
|
||||
@ -218,7 +247,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPublishHandlerForPlay(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
public void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
|
||||
StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid);
|
||||
@ -228,14 +257,6 @@ public class PlayServiceImpl implements IPlayService {
|
||||
deviceChannel.setStreamId(streamInfo.getStreamId());
|
||||
storager.startPlay(deviceId, channelId, streamInfo.getStreamId());
|
||||
}
|
||||
ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId);
|
||||
SIPDialog dialog = (SIPDialog)transaction.getDialog();
|
||||
StreamInfo.TransactionInfo transactionInfo = new StreamInfo.TransactionInfo();
|
||||
transactionInfo.callId = dialog.getCallId().getCallId();
|
||||
transactionInfo.localTag = dialog.getLocalTag();
|
||||
transactionInfo.remoteTag = dialog.getRemoteTag();
|
||||
transactionInfo.branch = dialog.getFirstTransactionInt().getBranchId();
|
||||
streamInfo.setTransactionInfo(transactionInfo);
|
||||
redisCatchStorage.startPlay(streamInfo);
|
||||
msg.setData(JSON.toJSONString(streamInfo));
|
||||
|
||||
@ -254,10 +275,10 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMediaServerItem getNewMediaServerItem(Device device) {
|
||||
public MediaServerItem getNewMediaServerItem(Device device) {
|
||||
if (device == null) return null;
|
||||
String mediaServerId = device.getMediaServerId();
|
||||
IMediaServerItem mediaServerItem = null;
|
||||
MediaServerItem mediaServerItem = null;
|
||||
if (mediaServerId == null) {
|
||||
mediaServerItem = mediaServerService.getMediaServerForMinimumLoad();
|
||||
}else {
|
||||
@ -270,7 +291,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPublishHandlerForPlayBack(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
public void onPublishHandlerForPlayBack(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
RequestMessage msg = new RequestMessage();
|
||||
msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
|
||||
StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid);
|
||||
@ -285,7 +306,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
}
|
||||
|
||||
public StreamInfo onPublishHandler(IMediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
|
||||
String streamId = resonse.getString("stream");
|
||||
JSONArray tracks = resonse.getJSONArray("tracks");
|
||||
StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem,"rtp", streamId, tracks);
|
||||
|
@ -3,7 +3,6 @@ package com.genersoft.iot.vmp.service.impl;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||
import com.genersoft.iot.vmp.service.IGbStreamService;
|
||||
@ -58,7 +57,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
|
||||
@Override
|
||||
public String save(StreamProxyItem param) {
|
||||
IMediaServerItem mediaInfo;
|
||||
MediaServerItem mediaInfo;
|
||||
if ("auto".equals(param.getMediaServerId())){
|
||||
mediaInfo = mediaServerService.getMediaServerForMinimumLoad();
|
||||
}else {
|
||||
@ -120,7 +119,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
@Override
|
||||
public JSONObject addStreamProxyToZlm(StreamProxyItem param) {
|
||||
JSONObject result = null;
|
||||
IMediaServerItem mediaServerItem = null;
|
||||
MediaServerItem mediaServerItem = null;
|
||||
if (param.getMediaServerId() == null) {
|
||||
logger.warn("添加代理时MediaServerId 为null");
|
||||
return null;
|
||||
@ -141,7 +140,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
@Override
|
||||
public JSONObject removeStreamProxyFromZlm(StreamProxyItem param) {
|
||||
if (param ==null) return null;
|
||||
IMediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
|
||||
MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
|
||||
JSONObject result = zlmresTfulUtils.closeStreams(mediaServerItem, param.getApp(), param.getStream());
|
||||
return result;
|
||||
}
|
||||
@ -198,7 +197,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getFFmpegCMDs(IMediaServerItem mediaServerItem) {
|
||||
public JSONObject getFFmpegCMDs(MediaServerItem mediaServerItem) {
|
||||
JSONObject result = new JSONObject();
|
||||
JSONObject mediaServerConfigResuly = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
|
||||
if (mediaServerConfigResuly != null && mediaServerConfigResuly.getInteger("code") == 0
|
||||
|
@ -5,7 +5,6 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||
@ -43,7 +42,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Override
|
||||
public List<StreamPushItem> handleJSON(String jsonData, IMediaServerItem mediaServerItem) {
|
||||
public List<StreamPushItem> handleJSON(String jsonData, MediaServerItem mediaServerItem) {
|
||||
if (jsonData == null) return null;
|
||||
|
||||
Map<String, StreamPushItem> result = new HashMap<>();
|
||||
@ -98,7 +97,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
|
||||
@Override
|
||||
public boolean removeFromGB(GbStream stream) {
|
||||
int del = gbStreamMapper.del(stream.getApp(), stream.getStream());
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(stream.getMediaServerId());
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(stream.getMediaServerId());
|
||||
JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, stream.getApp(), stream.getStream());
|
||||
if (mediaList == null) {
|
||||
streamPushMapper.del(stream.getApp(), stream.getStream());
|
||||
|
@ -5,8 +5,6 @@ import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -3,7 +3,6 @@ package com.genersoft.iot.vmp.storager;
|
||||
import java.util.List;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.genersoft.iot.vmp.storager.dao;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
@ -35,6 +33,7 @@ public interface MediaServerMapper {
|
||||
"rtpEnable, " +
|
||||
"rtpPortRange, " +
|
||||
"recordAssistPort, " +
|
||||
"defaultServer, " +
|
||||
"createTime, " +
|
||||
"updateTime" +
|
||||
") VALUES " +
|
||||
@ -57,9 +56,10 @@ public interface MediaServerMapper {
|
||||
"${rtpEnable}, " +
|
||||
"'${rtpPortRange}', " +
|
||||
"${recordAssistPort}, " +
|
||||
"${defaultServer}, " +
|
||||
"'${createTime}', " +
|
||||
"'${updateTime}')")
|
||||
int add(IMediaServerItem mediaServerItem);
|
||||
int add(MediaServerItem mediaServerItem);
|
||||
|
||||
@Update(value = {" <script>" +
|
||||
"UPDATE media_server " +
|
||||
@ -83,7 +83,7 @@ public interface MediaServerMapper {
|
||||
"<if test=\"recordAssistPort != null\">, recordAssistPort=${recordAssistPort}</if>" +
|
||||
"WHERE id='${id}'"+
|
||||
" </script>"})
|
||||
int update(IMediaServerItem mediaServerItem);
|
||||
int update(MediaServerItem mediaServerItem);
|
||||
|
||||
@Select("SELECT * FROM media_server WHERE id='${id}'")
|
||||
MediaServerItem queryOne(String id);
|
||||
@ -92,7 +92,7 @@ public interface MediaServerMapper {
|
||||
List<MediaServerItem> queryAll();
|
||||
|
||||
@Select("DELETE FROM media_server WHERE id='${id}'")
|
||||
int delOne(String secret);
|
||||
void delOne(String id);
|
||||
|
||||
@Select("SELECT * FROM media_server WHERE ip='${host}' and httpPort=${port}")
|
||||
MediaServerItem queryOneByHostAndPort(String host, int port);
|
||||
|
@ -3,10 +3,7 @@ package com.genersoft.iot.vmp.storager.impl;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||
|
@ -0,0 +1,8 @@
|
||||
package com.genersoft.iot.vmp.utils;
|
||||
|
||||
public class ConfigConst {
|
||||
/**
|
||||
* 播流最大并发个数
|
||||
*/
|
||||
public static final Integer MAX_STRTEAM_COUNT = 10000;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.genersoft.iot.vmp.utils;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class SerializeUtils {
|
||||
public static byte[] serialize(Object obj){
|
||||
byte[] bytes = null;
|
||||
try {
|
||||
ByteArrayOutputStream baos=new ByteArrayOutputStream();;
|
||||
ObjectOutputStream oos=new ObjectOutputStream(baos);
|
||||
oos.writeObject(obj);
|
||||
bytes=baos.toByteArray();
|
||||
baos.close();
|
||||
oos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
public static Object deSerialize(byte[] bytes){
|
||||
Object obj=null;
|
||||
try {
|
||||
ByteArrayInputStream bais=new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois=new ObjectInputStream(bais);
|
||||
obj=ois.readObject();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -415,10 +415,10 @@ public class RedisUtil {
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @param score
|
||||
* @param delta -1 表示减 1 表示加1
|
||||
*/
|
||||
public Double zIncrScore(Object key, Object value, double score) {
|
||||
return redisTemplate.opsForZSet().incrementScore(key, value, score);
|
||||
public Double zIncrScore(Object key, Object value, double delta) {
|
||||
return redisTemplate.opsForZSet().incrementScore(key, value, delta);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,13 +2,12 @@ package com.genersoft.iot.vmp.vmanager.gb28181.play;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
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.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
@ -37,7 +36,7 @@ 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 java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -89,7 +88,7 @@ public class PlayController {
|
||||
|
||||
// 获取可用的zlm
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
IMediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
|
||||
MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
|
||||
PlayResult playResult = playService.play(newMediaServerItem, deviceId, channelId, null, null);
|
||||
|
||||
return playResult.getResult();
|
||||
@ -174,7 +173,7 @@ public class PlayController {
|
||||
logger.warn("视频转码API调用失败!, 视频流已经停止!");
|
||||
return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK);
|
||||
}
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(streamInfo.getMediaServerId());
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(streamInfo.getMediaServerId());
|
||||
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
|
||||
if (!rtpInfo.getBoolean("exist")) {
|
||||
logger.warn("视频转码API调用失败!, 视频流已停止推流!");
|
||||
@ -219,7 +218,7 @@ public class PlayController {
|
||||
result.put("msg", "mediaServerId is null");
|
||||
return new ResponseEntity<String>( result.toJSONString(), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
IMediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo == null) {
|
||||
result.put("code", 0);
|
||||
result.put("msg", "使用的流媒体已经停止运行");
|
||||
@ -307,16 +306,16 @@ public class PlayController {
|
||||
logger.debug("获取所有的ssrc");
|
||||
}
|
||||
JSONArray objects = new JSONArray();
|
||||
for(Map.Entry<String, String> entry: streamSession.getSsrcMap().entrySet()) {
|
||||
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
|
||||
List<SsrcTransaction> allSsrc = streamSession.getAllSsrc();
|
||||
for (SsrcTransaction transaction : allSsrc) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
String[] keyArray = entry.getKey().split("_");
|
||||
jsonObject.put("deviceId", keyArray[0]);
|
||||
jsonObject.put("channelId", keyArray[1]);
|
||||
jsonObject.put("ssrc", entry.getValue());
|
||||
jsonObject.put("streamId", streamSession.getStreamIdMap().get(entry.getKey()));
|
||||
jsonObject.put("deviceId", transaction.getDeviceId());
|
||||
jsonObject.put("channelId", transaction.getChannelId());
|
||||
jsonObject.put("ssrc", transaction.getSsrc());
|
||||
jsonObject.put("streamId", transaction.getStreamId());
|
||||
objects.add(jsonObject);
|
||||
}
|
||||
|
||||
WVPResult<JSONObject> result = new WVPResult<>();
|
||||
result.setCode(0);
|
||||
result.setMsg("success");
|
||||
|
@ -3,9 +3,9 @@ package com.genersoft.iot.vmp.vmanager.gb28181.playback;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
||||
//import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.service.IPlayService;
|
||||
import io.swagger.annotations.Api;
|
||||
@ -58,6 +58,9 @@ public class DownloadController {
|
||||
@Autowired
|
||||
private DeferredResultHolder resultHolder;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@ApiOperation("开始历史媒体下载")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
|
||||
@ -90,7 +93,7 @@ public class DownloadController {
|
||||
cmder.streamByeCmd(deviceId, channelId);
|
||||
}
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
|
||||
IMediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
|
||||
MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
|
||||
if (newMediaServerItem == null) {
|
||||
logger.warn(String.format("设备下载响应超时,deviceId:%s ,channelId:%s", deviceId, channelId));
|
||||
RequestMessage msg = new RequestMessage();
|
||||
@ -99,7 +102,10 @@ public class DownloadController {
|
||||
resultHolder.invokeResult(msg);
|
||||
return result;
|
||||
}
|
||||
cmder.downloadStreamCmd(newMediaServerItem, device, channelId, startTime, endTime, downloadSpeed, (IMediaServerItem mediaServerItem, JSONObject response) -> {
|
||||
|
||||
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null);
|
||||
|
||||
cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (MediaServerItem mediaServerItem, JSONObject response) -> {
|
||||
logger.info("收到订阅消息: " + response.toJSONString());
|
||||
playService.onPublishHandlerForPlayBack(mediaServerItem, response, deviceId, channelId, uuid.toString());
|
||||
}, event -> {
|
||||
|
@ -4,8 +4,9 @@ import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
||||
//import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.service.IPlayService;
|
||||
import io.swagger.annotations.Api;
|
||||
@ -58,6 +59,9 @@ public class PlaybackController {
|
||||
@Autowired
|
||||
private DeferredResultHolder resultHolder;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@ApiOperation("开始视频回放")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
|
||||
@ -74,6 +78,15 @@ public class PlaybackController {
|
||||
}
|
||||
UUID uuid = UUID.randomUUID();
|
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(30000L);
|
||||
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
if (device == null) {
|
||||
result.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
|
||||
return result;
|
||||
}
|
||||
MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
|
||||
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null);
|
||||
|
||||
// 超时处理
|
||||
result.onTimeout(()->{
|
||||
logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
|
||||
@ -82,14 +95,14 @@ public class PlaybackController {
|
||||
msg.setData("Timeout");
|
||||
resultHolder.invokeResult(msg);
|
||||
});
|
||||
Device device = storager.queryVideoDevice(deviceId);
|
||||
|
||||
StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId);
|
||||
if (streamInfo != null) {
|
||||
// 停止之前的回放
|
||||
cmder.streamByeCmd(deviceId, channelId);
|
||||
}
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
|
||||
IMediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
|
||||
|
||||
if (newMediaServerItem == null) {
|
||||
logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
|
||||
RequestMessage msg = new RequestMessage();
|
||||
@ -98,7 +111,8 @@ public class PlaybackController {
|
||||
resultHolder.invokeResult(msg);
|
||||
return result;
|
||||
}
|
||||
cmder.playbackStreamCmd(newMediaServerItem, device, channelId, startTime, endTime, (IMediaServerItem mediaServerItem, JSONObject response) -> {
|
||||
|
||||
cmder.playbackStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, (MediaServerItem mediaServerItem, JSONObject response) -> {
|
||||
logger.info("收到订阅消息: " + response.toJSONString());
|
||||
playService.onPublishHandlerForPlayBack(mediaServerItem, response, deviceId, channelId, uuid.toString());
|
||||
}, event -> {
|
||||
|
@ -0,0 +1,23 @@
|
||||
package com.genersoft.iot.vmp.vmanager.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,10 +1,8 @@
|
||||
package com.genersoft.iot.vmp.vmanager.server;
|
||||
|
||||
import com.genersoft.iot.vmp.VManageBootstrap;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import gov.nist.javax.sip.SipStackImpl;
|
||||
@ -17,7 +15,6 @@ import org.springframework.web.bind.annotation.*;
|
||||
import javax.sip.ListeningPoint;
|
||||
import javax.sip.ObjectInUseException;
|
||||
import javax.sip.SipProvider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@ -38,19 +35,30 @@ public class ServerController {
|
||||
@ApiOperation("流媒体服务列表")
|
||||
@GetMapping(value = "/media_server/list")
|
||||
@ResponseBody
|
||||
public WVPResult<List<IMediaServerItem>> getMediaServerList(){
|
||||
WVPResult<List<IMediaServerItem>> result = new WVPResult<>();
|
||||
public WVPResult<List<MediaServerItem>> getMediaServerList(){
|
||||
WVPResult<List<MediaServerItem>> result = new WVPResult<>();
|
||||
result.setCode(0);
|
||||
result.setMsg("success");
|
||||
result.setData(mediaServerService.getAll());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ApiOperation("在线流媒体服务列表")
|
||||
@GetMapping(value = "/media_server/online/list")
|
||||
@ResponseBody
|
||||
public WVPResult<List<MediaServerItem>> getOnlineMediaServerList(){
|
||||
WVPResult<List<MediaServerItem>> result = new WVPResult<>();
|
||||
result.setCode(0);
|
||||
result.setMsg("success");
|
||||
result.setData(mediaServerService.getAllOnline());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ApiOperation("获取流媒体服务")
|
||||
@GetMapping(value = "/media_server/one/{id}")
|
||||
@ResponseBody
|
||||
public WVPResult<IMediaServerItem> getMediaServer(@PathVariable String id){
|
||||
WVPResult<IMediaServerItem> result = new WVPResult<>();
|
||||
public WVPResult<MediaServerItem> getMediaServer(@PathVariable String id){
|
||||
WVPResult<MediaServerItem> result = new WVPResult<>();
|
||||
result.setCode(0);
|
||||
result.setMsg("success");
|
||||
result.setData(mediaServerService.getOne(id));
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.genersoft.iot.vmp.vmanager.streamProxy;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IMediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
@ -9,7 +8,6 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.service.IStreamProxyService;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
@ -86,7 +84,7 @@ public class StreamProxyController {
|
||||
public WVPResult getFFmpegCMDs(@RequestParam String mediaServerId){
|
||||
logger.debug("获取节点[ {} ]ffmpeg.cmd模板", mediaServerId );
|
||||
|
||||
IMediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
JSONObject data = streamProxyService.getFFmpegCMDs(mediaServerItem);
|
||||
WVPResult<JSONObject> result = new WVPResult<>();
|
||||
result.setCode(0);
|
||||
|
@ -17,6 +17,12 @@ spring:
|
||||
password:
|
||||
# [可选] 超时时间
|
||||
timeout: 10000
|
||||
# [可选] 一个pool最多可分配多少个jedis实例
|
||||
poolMaxTotal: 1000
|
||||
# [可选] 一个pool最多有多少个状态为idle(空闲)的jedis实例
|
||||
poolMaxIdle: 500
|
||||
# [可选] 最大的等待时间(秒)
|
||||
poolMaxWait: 5
|
||||
# [可选] jdbc数据库配置, 项目使用sqlite作为数据库,一般不需要配置
|
||||
datasource:
|
||||
# 使用mysql 打开23-28行注释, 删除29-36行
|
||||
@ -124,6 +130,7 @@ logging:
|
||||
level:
|
||||
com.genersoft.iot: debug
|
||||
com.genersoft.iot.vmp.storager.dao: info
|
||||
com.genersoft.iot.vmp.gb28181: info
|
||||
# [根据业务需求配置]
|
||||
user-settings:
|
||||
# [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true
|
||||
|
@ -76,6 +76,8 @@ logging:
|
||||
level:
|
||||
com.genersoft.iot: debug
|
||||
com.genersoft.iot.vmp.storager.dao: info
|
||||
com.genersoft.iot.vmp.gb28181: info
|
||||
|
||||
# [根据业务需求配置]
|
||||
user-settings:
|
||||
# 推流直播是否录制
|
||||
|
Binary file not shown.
@ -9,7 +9,7 @@ class MediaServer{
|
||||
getMediaServerList(callback){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/server/media_server/list`,
|
||||
url:`/api/server/media_server/online/list`,
|
||||
}).then(function (res) {
|
||||
if (typeof (callback) == "function") callback(res.data)
|
||||
}).catch(function (error) {
|
||||
|
Loading…
Reference in New Issue
Block a user