第一次提交
This commit is contained in:
29
fastbee-server/sip-server/README.md
Normal file
29
fastbee-server/sip-server/README.md
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
## GB28181 Roadmap
|
||||
- 设备基础信息上报
|
||||
- 物模型适配(属性,功能)
|
||||
- 设备直播
|
||||
- 设备录像拉取
|
||||
- PTZ云台控制
|
||||
- 设备自动拉流 云端录像
|
||||
- tcp传输信令
|
||||
- 添加事件处理机制
|
||||
- srs m7s流媒体服务器支持
|
||||
- 百度evs,七牛云qvs等云平台api对接
|
||||
|
||||
## webhook
|
||||
- on_http_access
|
||||
- on_play
|
||||
- on_publish
|
||||
- on_stream_none_reader //StopPlay
|
||||
- on_stream_not_found
|
||||
- on_stream_changed
|
||||
|
||||
## zlm api
|
||||
- url + "/index/api/getRtpInfo?secret=" + secret + "&stream_id=" + ssrc 获取流在zlm上的信息
|
||||
- url + "/index/api/openRtpServer?secret=" + secret + "&port=0&enable_tcp=1&stream_id=" + streamId + "&ssrc=" + ssrc 创建GB28181 RTP接收端口
|
||||
- url + "/index/api/closeRtpServer?secret=" + secret + "&stream_id=" + streamId 关闭GB28181 RTP接收端口
|
||||
- url + "/index/api/listRtpServer?secret=" + secret 获取RTP服务器
|
||||
- url + "/index/api/close_streams?secret=" + secret + "&stream=" + ssrc 关闭流
|
||||
- url + "/index/api/getMediaList?secret=" + secret + "&stream=" + ssrc 获取流信息
|
||||
|
77
fastbee-server/sip-server/pom.xml
Normal file
77
fastbee-server/sip-server/pom.xml
Normal file
@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>fastbee-server</artifactId>
|
||||
<groupId>com.fastbee</groupId>
|
||||
<version>3.8.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>sip-server</artifactId>
|
||||
<description>GB28181信令服务</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- httpclient -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- ttl -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>transmittable-thread-local</artifactId>
|
||||
<version>2.14.0</version>
|
||||
</dependency>
|
||||
<!-- sip -->
|
||||
<dependency>
|
||||
<groupId>javax.sip</groupId>
|
||||
<artifactId>jain-sip-ri</artifactId>
|
||||
<version>1.3.0-91</version>
|
||||
</dependency>
|
||||
<!-- xml解析库 -->
|
||||
<dependency>
|
||||
<groupId>org.dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>2.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.log4j</groupId>
|
||||
<artifactId>com.springsource.org.apache.log4j</artifactId>
|
||||
<version>1.2.16</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fastbee</groupId>
|
||||
<artifactId>fastbee-mqtt-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fastbee</groupId>
|
||||
<artifactId>fastbee-oss</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,20 @@
|
||||
package com.fastbee.sip.conf;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "sip")
|
||||
public class SysSipConfig {
|
||||
boolean enabled;
|
||||
String ip;
|
||||
Integer port;
|
||||
String domain;
|
||||
String id;
|
||||
String password;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.fastbee.sip.conf;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
@Configuration
|
||||
@EnableAsync(proxyTargetClass = true)
|
||||
public class ThreadPoolTaskConfig {
|
||||
public static final int cpuNum = Runtime.getRuntime().availableProcessors();
|
||||
private static final int corePoolSize = cpuNum;
|
||||
private static final int maxPoolSize = cpuNum*2;
|
||||
private static final int keepAliveTime = 30;
|
||||
private static final int queueCapacity = 10000;
|
||||
private static final String threadNamePrefix = "sip-";
|
||||
|
||||
@Bean("taskExecutor")
|
||||
public ThreadPoolTaskExecutor taskExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(corePoolSize);
|
||||
executor.setMaxPoolSize(maxPoolSize);
|
||||
executor.setQueueCapacity(queueCapacity);
|
||||
executor.setKeepAliveSeconds(keepAliveTime);
|
||||
executor.setThreadNamePrefix(threadNamePrefix);
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.fastbee.sip.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author bill
|
||||
*/
|
||||
@Data
|
||||
public class BindingChannel {
|
||||
|
||||
/**
|
||||
* 监控设备ID
|
||||
*/
|
||||
private String channelId;
|
||||
|
||||
/**
|
||||
* 设备id
|
||||
*/
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
* 场景id
|
||||
*/
|
||||
private Long sceneModelId;
|
||||
|
||||
private String deviceName;
|
||||
private String sceneModelName;
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package com.fastbee.sip.domain;
|
||||
|
||||
import com.fastbee.common.annotation.Excel;
|
||||
import com.fastbee.common.core.domain.BaseEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 流媒体服务器配置对象 media_server
|
||||
*
|
||||
* @author zhuangpeng.li
|
||||
* @date 2022-11-30
|
||||
*/
|
||||
@ApiModel(value = "MediaServer", description = "流媒体服务器配置对象 media_server")
|
||||
@Data
|
||||
public class MediaServer extends BaseEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 流媒体配置ID */
|
||||
@ApiModelProperty("流媒体配置ID")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("服务器标识")
|
||||
private String serverId;
|
||||
|
||||
/** 租户ID */
|
||||
@ApiModelProperty("租户ID")
|
||||
@Excel(name = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
/** 租户名称 */
|
||||
@ApiModelProperty("租户名称")
|
||||
@Excel(name = "租户名称")
|
||||
private String tenantName;
|
||||
|
||||
/** 是否系统通用(0-否,1-是) */
|
||||
@ApiModelProperty(value = "是否系统通用", notes = "(0-否,1-是)")
|
||||
@Excel(name = "是否系统通用", readConverterExp = "0=-否,1-是")
|
||||
private Integer isSys;
|
||||
|
||||
/** 使能开关 */
|
||||
@ApiModelProperty("使能开关")
|
||||
@Excel(name = "使能开关")
|
||||
private Integer enabled;
|
||||
|
||||
/** 默认播放协议 */
|
||||
@ApiModelProperty("默认播放协议")
|
||||
@Excel(name = "默认播放协议")
|
||||
private String protocol;
|
||||
|
||||
@ApiModelProperty("回调服务器地址")
|
||||
@Excel(name = "回调服务器地址")
|
||||
private String hookurl;
|
||||
|
||||
/** 服务器ip */
|
||||
@ApiModelProperty("服务器ip")
|
||||
@Excel(name = "服务器ip")
|
||||
private String ip;
|
||||
|
||||
/** 服务器域名 */
|
||||
@ApiModelProperty("服务器域名")
|
||||
@Excel(name = "服务器域名")
|
||||
private String domain;
|
||||
|
||||
/** 流媒体密钥 */
|
||||
@ApiModelProperty("流媒体密钥")
|
||||
@Excel(name = "流媒体密钥")
|
||||
private String secret;
|
||||
|
||||
/** http端口 */
|
||||
@ApiModelProperty("http端口")
|
||||
@Excel(name = "http端口")
|
||||
private Long portHttp;
|
||||
|
||||
/** ws端口 */
|
||||
@ApiModelProperty("ws端口")
|
||||
@Excel(name = "HTTPS端口")
|
||||
private Long portHttps;
|
||||
|
||||
/** rtmp端口 */
|
||||
@ApiModelProperty("rtmp端口")
|
||||
@Excel(name = "rtmp端口")
|
||||
private Long portRtmp;
|
||||
|
||||
/** rtsp端口 */
|
||||
@ApiModelProperty("rtsp端口")
|
||||
@Excel(name = "rtsp端口")
|
||||
private Long portRtsp;
|
||||
|
||||
@ApiModelProperty("RTP收流端口")
|
||||
@Excel(name = "RTP收流端口(单端口模式有用)")
|
||||
private Long rtpProxyPort;
|
||||
|
||||
@ApiModelProperty("是否使用多端口模式")
|
||||
@Excel(name = "是否使用多端口模式")
|
||||
private Integer rtpEnable;
|
||||
|
||||
/** rtp端口范围 */
|
||||
@ApiModelProperty("rtp端口范围")
|
||||
@Excel(name = "rtp端口范围")
|
||||
private String rtpPortRange;
|
||||
|
||||
@ApiModelProperty("是否自动同步配置ZLM")
|
||||
@Excel(name = "是否自动同步配置ZLM")
|
||||
private Integer autoConfig;
|
||||
|
||||
@ApiModelProperty("状态")
|
||||
@Excel(name = "状态")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("录像服务端口")
|
||||
@Excel(name = "录像服务端口")
|
||||
private Long recordPort;
|
||||
|
||||
/** 删除标志(0代表存在 2代表删除) */
|
||||
@ApiModelProperty("删除标志")
|
||||
private String delFlag;
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package com.fastbee.sip.domain;
|
||||
|
||||
import com.fastbee.common.annotation.Excel;
|
||||
import com.fastbee.common.core.domain.BaseEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* sip系统配置对象 sip_config
|
||||
*
|
||||
* @author zhuangpeng.li
|
||||
* @date 2023-02-21
|
||||
*/
|
||||
@ApiModel(value = "SipConfig", description = "sip系统配置对象 sip_config")
|
||||
@Data
|
||||
public class SipConfig extends BaseEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 配置ID */
|
||||
@ApiModelProperty("配置ID")
|
||||
private Long id;
|
||||
|
||||
/** 是否系统通用(0-否,1-是) */
|
||||
@ApiModelProperty(value = "是否系统通用", notes = "(0-否,1-是)")
|
||||
@Excel(name = "是否系统通用", readConverterExp = "0=-否,1-是")
|
||||
private Integer isSys;
|
||||
|
||||
/** 产品ID */
|
||||
@ApiModelProperty("产品ID")
|
||||
@Excel(name = "产品ID")
|
||||
private Long productId;
|
||||
|
||||
/**
|
||||
* 产品名称
|
||||
*/
|
||||
@ApiModelProperty("产品名称")
|
||||
@Excel(name = "产品名称")
|
||||
private String productName;
|
||||
|
||||
/**
|
||||
* 使能开关
|
||||
*/
|
||||
@ApiModelProperty("使能开关")
|
||||
@Excel(name = "使能开关")
|
||||
private Integer enabled;
|
||||
|
||||
/**
|
||||
* 系统默认配置
|
||||
*/
|
||||
@ApiModelProperty("系统默认配置")
|
||||
@Excel(name = "系统默认配置")
|
||||
private Integer isdefault;
|
||||
|
||||
/**
|
||||
* 拓展sdp
|
||||
*/
|
||||
@ApiModelProperty("拓展sdp")
|
||||
@Excel(name = "拓展sdp")
|
||||
private Integer seniorsdp;
|
||||
|
||||
/**
|
||||
* 服务器域
|
||||
*/
|
||||
@ApiModelProperty("服务器域")
|
||||
@Excel(name = "服务器域")
|
||||
private String domain;
|
||||
|
||||
/**
|
||||
* 服务器sipid
|
||||
*/
|
||||
@ApiModelProperty("服务器sipid")
|
||||
@Excel(name = "服务器sipid")
|
||||
private String serverSipid;
|
||||
|
||||
/** sip认证密码 */
|
||||
@ApiModelProperty("sip认证密码")
|
||||
@Excel(name = "sip认证密码")
|
||||
private String password;
|
||||
|
||||
/** sip接入IP */
|
||||
@ApiModelProperty("sip接入IP")
|
||||
@Excel(name = "sip接入IP")
|
||||
private String ip;
|
||||
|
||||
/** sip接入端口号 */
|
||||
@ApiModelProperty("sip接入端口号")
|
||||
@Excel(name = "sip接入端口号")
|
||||
private Integer port;
|
||||
|
||||
/** 删除标志(0代表存在 2代表删除) */
|
||||
@ApiModelProperty("删除标志")
|
||||
private String delFlag;
|
||||
}
|
@ -0,0 +1,310 @@
|
||||
package com.fastbee.sip.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fastbee.common.annotation.Excel;
|
||||
import com.fastbee.common.core.domain.BaseEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 监控设备对象 sip_device
|
||||
*
|
||||
* @author zhuangpeng.li
|
||||
* @date 2023-02-24
|
||||
*/
|
||||
@ApiModel(value = "SipDevice", description = "监控设备对象 sip_device")
|
||||
public class SipDevice extends BaseEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 设备ID */
|
||||
@ApiModelProperty("设备ID")
|
||||
private Long deviceId;
|
||||
|
||||
/** 产品ID */
|
||||
@ApiModelProperty("产品ID")
|
||||
@Excel(name = "产品ID")
|
||||
private Long productId;
|
||||
|
||||
/** 产品名称 */
|
||||
@ApiModelProperty("产品名称")
|
||||
@Excel(name = "产品名称")
|
||||
private String productName;
|
||||
|
||||
/** 设备SipID */
|
||||
@ApiModelProperty("设备SipID")
|
||||
@Excel(name = "设备SipID")
|
||||
private String deviceSipId;
|
||||
|
||||
/** 设备名称 */
|
||||
@ApiModelProperty("设备名称")
|
||||
@Excel(name = "设备名称")
|
||||
private String deviceName;
|
||||
|
||||
/** 厂商名称 */
|
||||
@ApiModelProperty("厂商名称")
|
||||
@Excel(name = "厂商名称")
|
||||
private String manufacturer;
|
||||
|
||||
/** 产品型号 */
|
||||
@ApiModelProperty("产品型号")
|
||||
@Excel(name = "产品型号")
|
||||
private String model;
|
||||
|
||||
/** 固件版本 */
|
||||
@ApiModelProperty("固件版本")
|
||||
@Excel(name = "固件版本")
|
||||
private String firmware;
|
||||
|
||||
/** 传输模式 */
|
||||
@ApiModelProperty("传输模式")
|
||||
@Excel(name = "传输模式")
|
||||
private String transport;
|
||||
|
||||
/** 流模式 */
|
||||
@ApiModelProperty("流模式")
|
||||
@Excel(name = "流模式")
|
||||
private String streammode;
|
||||
|
||||
/** 在线状态 */
|
||||
@ApiModelProperty("在线状态")
|
||||
@Excel(name = "在线状态")
|
||||
private String online;
|
||||
|
||||
/** 注册时间 */
|
||||
@ApiModelProperty("注册时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@Excel(name = "注册时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date registertime;
|
||||
|
||||
/** 最后上线时间 */
|
||||
@ApiModelProperty("最后上线时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@Excel(name = "最后上线时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date lastconnecttime;
|
||||
|
||||
/** 激活时间 */
|
||||
@ApiModelProperty("激活时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@Excel(name = "激活时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date activeTime;
|
||||
|
||||
/** 设备入网IP */
|
||||
@ApiModelProperty("设备入网IP")
|
||||
@Excel(name = "设备入网IP")
|
||||
private String ip;
|
||||
|
||||
/** 设备接入端口号 */
|
||||
@ApiModelProperty("设备接入端口号")
|
||||
@Excel(name = "设备接入端口号")
|
||||
private Integer port;
|
||||
|
||||
/** 设备地址 */
|
||||
@ApiModelProperty("设备地址")
|
||||
@Excel(name = "设备地址")
|
||||
private String hostaddress;
|
||||
|
||||
/** 删除标志(0代表存在 2代表删除) */
|
||||
@ApiModelProperty("删除标志")
|
||||
private String delFlag;
|
||||
|
||||
public void setDeviceId(Long deviceId)
|
||||
{
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public Long getDeviceId()
|
||||
{
|
||||
return deviceId;
|
||||
}
|
||||
public void setProductId(Long productId)
|
||||
{
|
||||
this.productId = productId;
|
||||
}
|
||||
|
||||
public Long getProductId()
|
||||
{
|
||||
return productId;
|
||||
}
|
||||
public void setProductName(String productName)
|
||||
{
|
||||
this.productName = productName;
|
||||
}
|
||||
|
||||
public String getProductName()
|
||||
{
|
||||
return productName;
|
||||
}
|
||||
public void setDeviceSipId(String deviceSipId)
|
||||
{
|
||||
this.deviceSipId = deviceSipId;
|
||||
}
|
||||
|
||||
public String getDeviceSipId()
|
||||
{
|
||||
return deviceSipId;
|
||||
}
|
||||
public void setDeviceName(String deviceName)
|
||||
{
|
||||
this.deviceName = deviceName;
|
||||
}
|
||||
|
||||
public String getDeviceName()
|
||||
{
|
||||
return deviceName;
|
||||
}
|
||||
public void setManufacturer(String manufacturer)
|
||||
{
|
||||
this.manufacturer = manufacturer;
|
||||
}
|
||||
|
||||
public String getManufacturer()
|
||||
{
|
||||
return manufacturer;
|
||||
}
|
||||
public void setModel(String model)
|
||||
{
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public String getModel()
|
||||
{
|
||||
return model;
|
||||
}
|
||||
public void setFirmware(String firmware)
|
||||
{
|
||||
this.firmware = firmware;
|
||||
}
|
||||
|
||||
public String getFirmware()
|
||||
{
|
||||
return firmware;
|
||||
}
|
||||
public void setTransport(String transport)
|
||||
{
|
||||
this.transport = transport;
|
||||
}
|
||||
|
||||
public String getTransport()
|
||||
{
|
||||
return transport;
|
||||
}
|
||||
public void setStreammode(String streammode)
|
||||
{
|
||||
this.streammode = streammode;
|
||||
}
|
||||
|
||||
public String getStreammode()
|
||||
{
|
||||
return streammode;
|
||||
}
|
||||
public void setOnline(String online)
|
||||
{
|
||||
this.online = online;
|
||||
}
|
||||
|
||||
public String getOnline()
|
||||
{
|
||||
return online;
|
||||
}
|
||||
public void setRegistertime(Date registertime)
|
||||
{
|
||||
this.registertime = registertime;
|
||||
}
|
||||
|
||||
public Date getRegistertime()
|
||||
{
|
||||
return registertime;
|
||||
}
|
||||
public void setLastconnecttime(Date lastconnecttime)
|
||||
{
|
||||
this.lastconnecttime = lastconnecttime;
|
||||
}
|
||||
|
||||
public Date getLastconnecttime()
|
||||
{
|
||||
return lastconnecttime;
|
||||
}
|
||||
public void setActiveTime(Date activeTime)
|
||||
{
|
||||
this.activeTime = activeTime;
|
||||
}
|
||||
|
||||
public Date getActiveTime()
|
||||
{
|
||||
return activeTime;
|
||||
}
|
||||
public void setIp(String ip)
|
||||
{
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public String getIp()
|
||||
{
|
||||
return ip;
|
||||
}
|
||||
public void setPort(Integer port)
|
||||
{
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public Integer getPort()
|
||||
{
|
||||
return port;
|
||||
}
|
||||
public void setHostaddress(String hostaddress)
|
||||
{
|
||||
this.hostaddress = hostaddress;
|
||||
}
|
||||
|
||||
public String getHostaddress()
|
||||
{
|
||||
return hostaddress;
|
||||
}
|
||||
public void setDelFlag(String delFlag)
|
||||
{
|
||||
this.delFlag = delFlag;
|
||||
}
|
||||
|
||||
public String getDelFlag()
|
||||
{
|
||||
return delFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("deviceId", getDeviceId())
|
||||
.append("productId", getProductId())
|
||||
.append("productName", getProductName())
|
||||
.append("deviceSipId", getDeviceSipId())
|
||||
.append("deviceName", getDeviceName())
|
||||
.append("manufacturer", getManufacturer())
|
||||
.append("model", getModel())
|
||||
.append("firmware", getFirmware())
|
||||
.append("transport", getTransport())
|
||||
.append("streammode", getStreammode())
|
||||
.append("online", getOnline())
|
||||
.append("registertime", getRegistertime())
|
||||
.append("lastconnecttime", getLastconnecttime())
|
||||
.append("activeTime", getActiveTime())
|
||||
.append("ip", getIp())
|
||||
.append("port", getPort())
|
||||
.append("hostaddress", getHostaddress())
|
||||
.append("delFlag", getDelFlag())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("createTime", getCreateTime())
|
||||
.append("updateBy", getUpdateBy())
|
||||
.append("updateTime", getUpdateTime())
|
||||
.append("remark", getRemark())
|
||||
.toString();
|
||||
}
|
||||
|
||||
public String getHostAndPort() {
|
||||
return getIp() + ":" + getPort();
|
||||
}
|
||||
}
|
@ -0,0 +1,291 @@
|
||||
package com.fastbee.sip.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fastbee.common.annotation.Excel;
|
||||
import com.fastbee.common.core.domain.BaseEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 监控设备通道信息对象 sip_device_channel
|
||||
*
|
||||
* @author zhuangpeng.li
|
||||
* @date 2023-02-23
|
||||
*/
|
||||
@ApiModel(value = "SipDeviceChannel", description = "监控设备通道信息对象 sip_device_channel")
|
||||
@Data
|
||||
public class SipDeviceChannel extends BaseEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@ApiModelProperty("ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@ApiModelProperty("租户ID")
|
||||
@Excel(name = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 租户名称
|
||||
*/
|
||||
@ApiModelProperty("租户名称")
|
||||
@Excel(name = "租户名称")
|
||||
private String tenantName;
|
||||
|
||||
/**
|
||||
* 产品ID
|
||||
*/
|
||||
@ApiModelProperty("产品ID")
|
||||
@Excel(name = "产品ID")
|
||||
private Long productId;
|
||||
|
||||
/**
|
||||
* 产品名称
|
||||
*/
|
||||
@ApiModelProperty("产品名称")
|
||||
@Excel(name = "产品名称")
|
||||
private String productName;
|
||||
|
||||
/**
|
||||
* 产品ID
|
||||
*/
|
||||
@ApiModelProperty("产品ID")
|
||||
@Excel(name = "产品ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 产品名称
|
||||
*/
|
||||
@ApiModelProperty("产品名称")
|
||||
@Excel(name = "产品名称")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 设备SipID
|
||||
*/
|
||||
@ApiModelProperty("设备SipID")
|
||||
private String deviceSipId;
|
||||
|
||||
/**
|
||||
* 通道SipID
|
||||
*/
|
||||
@ApiModelProperty("通道SipID")
|
||||
@Excel(name = "通道SipID")
|
||||
private String channelSipId;
|
||||
|
||||
/**
|
||||
* 通道名称
|
||||
*/
|
||||
@ApiModelProperty("通道名称")
|
||||
@Excel(name = "通道名称")
|
||||
private String channelName;
|
||||
|
||||
/**
|
||||
* 注册时间
|
||||
*/
|
||||
@ApiModelProperty("注册时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@Excel(name = "注册时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date registerTime;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
@ApiModelProperty("设备类型")
|
||||
@Excel(name = "设备类型")
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 通道类型
|
||||
*/
|
||||
@ApiModelProperty("通道类型")
|
||||
@Excel(name = "通道类型")
|
||||
private String channelType;
|
||||
|
||||
/**
|
||||
* 城市编码
|
||||
*/
|
||||
@ApiModelProperty("城市编码")
|
||||
@Excel(name = "城市编码")
|
||||
private String citycode;
|
||||
|
||||
/**
|
||||
* 行政区域
|
||||
*/
|
||||
@ApiModelProperty("行政区域")
|
||||
@Excel(name = "行政区域")
|
||||
private String civilcode;
|
||||
|
||||
/**
|
||||
* 厂商名称
|
||||
*/
|
||||
@ApiModelProperty("厂商名称")
|
||||
@Excel(name = "厂商名称")
|
||||
private String manufacture;
|
||||
|
||||
/**
|
||||
* 产品型号
|
||||
*/
|
||||
@ApiModelProperty("产品型号")
|
||||
@Excel(name = "产品型号")
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 设备归属
|
||||
*/
|
||||
@ApiModelProperty("设备归属")
|
||||
@Excel(name = "设备归属")
|
||||
private String owner;
|
||||
|
||||
/**
|
||||
* 警区
|
||||
*/
|
||||
@ApiModelProperty("警区")
|
||||
@Excel(name = "警区")
|
||||
private String block;
|
||||
|
||||
/**
|
||||
* 安装地址
|
||||
*/
|
||||
@ApiModelProperty("安装地址")
|
||||
@Excel(name = "安装地址")
|
||||
private String address;
|
||||
|
||||
/** 父级id */
|
||||
@ApiModelProperty("父级id")
|
||||
@Excel(name = "父级id")
|
||||
private String parentid;
|
||||
|
||||
/** 设备入网IP */
|
||||
@ApiModelProperty("设备入网IP")
|
||||
@Excel(name = "设备入网IP")
|
||||
private String ipaddress;
|
||||
|
||||
/** 设备接入端口号 */
|
||||
@ApiModelProperty("设备接入端口号")
|
||||
@Excel(name = "设备接入端口号")
|
||||
private Integer port;
|
||||
|
||||
/** 密码 */
|
||||
@ApiModelProperty("密码")
|
||||
@Excel(name = "密码")
|
||||
private String password;
|
||||
|
||||
/** PTZ类型 */
|
||||
@ApiModelProperty("PTZ类型")
|
||||
@Excel(name = "PTZ类型")
|
||||
private Long ptztype;
|
||||
|
||||
/** PTZ类型描述字符串 */
|
||||
@ApiModelProperty("PTZ类型描述字符串")
|
||||
@Excel(name = "PTZ类型描述字符串")
|
||||
private String ptztypetext;
|
||||
|
||||
/**
|
||||
* 设备状态(1=-未使用,2-禁用,3-在线,4-离线)
|
||||
*/
|
||||
@ApiModelProperty("设备状态(1=-未使用,2-禁用,3-在线,4-离线)")
|
||||
@Excel(name = "设备状态", readConverterExp = "1=-未使用,2-禁用,3-在线,4-离线")
|
||||
private Integer status;
|
||||
/**
|
||||
* 推流状态(1-未使用,2-录像中)
|
||||
*/
|
||||
@ApiModelProperty("推流状态(1-未使用,2-录像中)")
|
||||
@Excel(name = "推流状态", readConverterExp = "1-未使用,2-录像中")
|
||||
private Integer streamPush;
|
||||
/**
|
||||
* 直播录像状态(1=-未使用,2-录像中)
|
||||
*/
|
||||
@ApiModelProperty("直播录像状态(1-未使用,2-录像中)")
|
||||
@Excel(name = "直播录像状态", readConverterExp = "1-未使用,2-录像中")
|
||||
private Integer streamRecord;
|
||||
|
||||
/**
|
||||
* 录像转存状态(1-未使用,2-录像中)
|
||||
*/
|
||||
@ApiModelProperty("录像转存状态(1-未使用,2-录像中)")
|
||||
@Excel(name = "录像转存状态", readConverterExp = "1-未使用,2-录像中")
|
||||
private Integer videoRecord;
|
||||
|
||||
/**
|
||||
* 设备经度
|
||||
*/
|
||||
@ApiModelProperty("设备经度")
|
||||
@Excel(name = "设备经度")
|
||||
private BigDecimal longitude;
|
||||
|
||||
/**
|
||||
* 设备纬度
|
||||
*/
|
||||
@ApiModelProperty("设备纬度")
|
||||
@Excel(name = "设备纬度")
|
||||
private BigDecimal latitude;
|
||||
|
||||
/**
|
||||
* 流媒体ID
|
||||
*/
|
||||
@ApiModelProperty("流媒体ID")
|
||||
@Excel(name = "流媒体ID")
|
||||
private String streamid;
|
||||
|
||||
/**
|
||||
* 子设备数
|
||||
*/
|
||||
@ApiModelProperty("子设备数")
|
||||
@Excel(name = "子设备数")
|
||||
private Long subcount;
|
||||
|
||||
/**
|
||||
* 是否有子设备(1-有, 0-没有)
|
||||
*/
|
||||
@ApiModelProperty("是否有子设备(1-有, 0-没有)")
|
||||
@Excel(name = "是否有子设备", readConverterExp = "1=-有,,0=-没有")
|
||||
private Integer parental;
|
||||
|
||||
/**
|
||||
* 是否含有音频(1-有, 0-没有)
|
||||
*/
|
||||
@ApiModelProperty("是否含有音频(1-有, 0-没有)")
|
||||
@Excel(name = "是否含有音频", readConverterExp = "1=-有,,0=-没有")
|
||||
private Integer hasaudio;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 2代表删除)
|
||||
*/
|
||||
@ApiModelProperty("删除标志(0代表存在 2代表删除)")
|
||||
private String delFlag;
|
||||
|
||||
@ApiModelProperty("关联信息")
|
||||
private BindingChannel bindingChannel;
|
||||
|
||||
/**
|
||||
* 设备id
|
||||
*/
|
||||
@ApiModelProperty("关联设备id")
|
||||
private Long reDeviceId;
|
||||
|
||||
/**
|
||||
* 直播流
|
||||
*/
|
||||
private String playUrl;
|
||||
|
||||
/**
|
||||
* 场景id
|
||||
*/
|
||||
@ApiModelProperty("关联场景id")
|
||||
private Long reSceneModelId;
|
||||
@ApiModelProperty("关联设备名称")
|
||||
private String reDeviceName;
|
||||
@ApiModelProperty("关联场景名称")
|
||||
private String reSceneModelName;
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.fastbee.sip.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum AlarmMethod {
|
||||
unknown("0", "未知"),
|
||||
telAlarm("1", "电话报警"),
|
||||
devAlarm("2", "设备报警"),
|
||||
smsAlarm("3", "短信报警"),
|
||||
gpsAlarm("4", "GPS报警"),
|
||||
videoAlarm("5", "视频报警"),
|
||||
devErrorAlarm("6", "设备故障报警"),
|
||||
other("7", "其他报警");
|
||||
private final String value;
|
||||
|
||||
private final String text;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package com.fastbee.sip.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum AlarmType {
|
||||
//设备报警
|
||||
videoLost("1", "视频丢失报警", AlarmMethod.devAlarm),
|
||||
videoBroken("2", "设备防拆报警", AlarmMethod.devAlarm),
|
||||
diskFull("3", "存储设备磁盘满报警", AlarmMethod.devAlarm),
|
||||
hot("4", "设备高温报警", AlarmMethod.devAlarm),
|
||||
cold("5", "设备低温报警", AlarmMethod.devAlarm),
|
||||
//视频报警
|
||||
manual("1", "人工视频报警", AlarmMethod.videoAlarm),
|
||||
moving("2", "运动目标检测报警", AlarmMethod.videoAlarm),
|
||||
residual("3", "遗留物检测报警", AlarmMethod.videoAlarm),
|
||||
remove("4", "物体移除检测报警", AlarmMethod.videoAlarm),
|
||||
tripLine("5", "绊线检测报警", AlarmMethod.videoAlarm),
|
||||
intrusion("6", "入侵检测报警", AlarmMethod.videoAlarm),
|
||||
retrograde("7", "逆行检测报警", AlarmMethod.videoAlarm),
|
||||
wandering("8", "徘徊检测报警", AlarmMethod.videoAlarm),
|
||||
density("9", "密度检测报警", AlarmMethod.videoAlarm),
|
||||
error("10", "视频异常检测报警", AlarmMethod.videoAlarm),
|
||||
fastMoving("11", "快速移动报警", AlarmMethod.videoAlarm),
|
||||
|
||||
//存储设备
|
||||
storageDiskError("1", "存储设备磁盘故障报警", AlarmMethod.devErrorAlarm),
|
||||
|
||||
storageFanError("2", "存储设备风扇故障报警", AlarmMethod.devErrorAlarm);
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String text;
|
||||
|
||||
private final AlarmMethod method;
|
||||
|
||||
private static final Map<AlarmMethod, Map<String, AlarmType>> fastMap = new EnumMap<>(AlarmMethod.class);
|
||||
|
||||
static {
|
||||
for (AlarmType value : AlarmType.values()) {
|
||||
fastMap.computeIfAbsent(value.method, (ignore) -> new HashMap<>())
|
||||
.put(value.code, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<AlarmType> of(AlarmMethod method, String code) {
|
||||
Map<String, AlarmType> mapping = fastMap.get(method);
|
||||
if (mapping == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(mapping.get(code));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.fastbee.sip.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum ChannelStatus {
|
||||
online("ON", "在线"),
|
||||
|
||||
lost("VLOST", "视频丢失"),
|
||||
defect("DEFECT", "故障"),
|
||||
add("ADD", "新增"),
|
||||
delete("DEL", "删除"),
|
||||
update("UPDATE", "更新"),
|
||||
offline("OFF", "离线"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String text;
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.fastbee.sip.enums;
|
||||
|
||||
public enum ChannelType{
|
||||
CivilCode, BusinessGroup,VirtualOrganization,Other
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.fastbee.sip.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DeviceChannelStatus {
|
||||
//1=-未使用,2-禁用,3-在线,4-离线
|
||||
notused(1),
|
||||
off(2),
|
||||
online(3),
|
||||
offline(4);
|
||||
private final Integer value;
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.fastbee.sip.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum Direct {
|
||||
UP(0x08),
|
||||
DOWN(0x04),
|
||||
LEFT(0x02),
|
||||
RIGHT(0x01),
|
||||
ZOOM_IN(0x10),
|
||||
ZOOM_OUT(0x20),
|
||||
STOP(0) {
|
||||
@Override
|
||||
public int merge(int code) {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(int code) {
|
||||
return code == 0;
|
||||
}
|
||||
};
|
||||
private final int code;
|
||||
|
||||
public int merge(int code) {
|
||||
return code | this.code;
|
||||
}
|
||||
|
||||
public boolean match(int code) {
|
||||
return (code & this.code) != 0;
|
||||
}
|
||||
|
||||
public static Direct[] values(int code) {
|
||||
return Arrays
|
||||
.stream(values())
|
||||
.filter(direct -> direct.match(code))
|
||||
.toArray(Direct[]::new);
|
||||
}
|
||||
|
||||
public static Direct[] values(String code) {
|
||||
String[] codes = code.toUpperCase().split(",");
|
||||
|
||||
return Arrays
|
||||
.stream(codes)
|
||||
.map(Direct::valueOf)
|
||||
.toArray(Direct[]::new);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.fastbee.sip.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum FunctionType {
|
||||
VIDEOPUSH("video_push", "设备推流"),
|
||||
AUDIOBROADCAST("audio_broadcast", "语音广播"),
|
||||
OTHER("other", "其他");
|
||||
private final String value;
|
||||
private final String text;
|
||||
public static FunctionType fromType(String Type) {
|
||||
for (FunctionType type : FunctionType.values()) {
|
||||
if (Objects.equals(type.getValue(), Type)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.fastbee.sip.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PTZCmd {
|
||||
out(32),
|
||||
in(16),
|
||||
up(8),
|
||||
down(4),
|
||||
left(2),
|
||||
right(1);
|
||||
|
||||
private final Integer value;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.fastbee.sip.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PTZType {
|
||||
unknown(0, "未知"),
|
||||
ball(1, "球机"),
|
||||
hemisphere(2, "半球机"),
|
||||
fixed(3, "固定抢机"),
|
||||
remoteControl(4, "遥控抢机");
|
||||
|
||||
private final Integer value;
|
||||
private final String text;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.fastbee.sip.enums;
|
||||
|
||||
public enum SessionType {
|
||||
play,
|
||||
playrecord,
|
||||
playback,
|
||||
download
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.fastbee.sip.handler;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
public interface IReqHandler {
|
||||
public void processMsg(RequestEvent evt);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.fastbee.sip.handler;
|
||||
|
||||
import javax.sip.ResponseEvent;
|
||||
import java.text.ParseException;
|
||||
|
||||
public interface IResHandler {
|
||||
public void processMsg(ResponseEvent evt) throws ParseException;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.fastbee.sip.handler.req;
|
||||
|
||||
import com.fastbee.sip.handler.IReqHandler;
|
||||
import com.fastbee.sip.server.IGBListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.SipException;
|
||||
import java.text.ParseException;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AckReqHandler extends ReqAbstractHandler implements InitializingBean, IReqHandler {
|
||||
@Autowired
|
||||
private IGBListener sipListener;
|
||||
|
||||
@Override
|
||||
public void processMsg(RequestEvent evt) {
|
||||
log.info("接收到ACK信息");
|
||||
try {
|
||||
responseAck(evt);
|
||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||
log.error("[回复ACK信息失败],{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String method = "ACK";
|
||||
sipListener.addRequestProcessor(method, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.fastbee.sip.handler.req;
|
||||
|
||||
import com.fastbee.sip.handler.IReqHandler;
|
||||
import com.fastbee.sip.server.IGBListener;
|
||||
import gov.nist.javax.sip.message.SIPRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.message.Response;
|
||||
import java.text.ParseException;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ByeReqHandler extends ReqAbstractHandler implements InitializingBean, IReqHandler {
|
||||
@Autowired
|
||||
private IGBListener sipListener;
|
||||
|
||||
@Override
|
||||
public void processMsg(RequestEvent evt) {
|
||||
log.info("接收到BYE信息");
|
||||
try {
|
||||
responseAck(evt);
|
||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||
log.error("[回复BYE信息失败],{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String method = "BYE";
|
||||
sipListener.addRequestProcessor(method, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.fastbee.sip.handler.req;
|
||||
|
||||
import com.fastbee.sip.handler.IReqHandler;
|
||||
import com.fastbee.sip.server.IGBListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.SipException;
|
||||
import java.text.ParseException;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CancelReqHandler extends ReqAbstractHandler implements InitializingBean, IReqHandler {
|
||||
@Autowired
|
||||
private IGBListener sipListener;
|
||||
|
||||
@Override
|
||||
public void processMsg(RequestEvent evt) {
|
||||
log.info("接收到CANCEL信息");
|
||||
try {
|
||||
responseAck(evt);
|
||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||
log.error("[回复CANCEL信息失败],{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String method = "CANCEL";
|
||||
sipListener.addRequestProcessor(method, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.fastbee.sip.handler.req;
|
||||
|
||||
import com.fastbee.sip.handler.IReqHandler;
|
||||
import com.fastbee.sip.server.IGBListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.SipException;
|
||||
import java.text.ParseException;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class InviteReqHandler extends ReqAbstractHandler implements InitializingBean, IReqHandler {
|
||||
@Autowired
|
||||
private IGBListener sipListener;
|
||||
|
||||
@Override
|
||||
public void processMsg(RequestEvent evt) {
|
||||
log.info("接收到INVITE信息");
|
||||
try {
|
||||
responseAck(evt);
|
||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||
log.error("[回复INVITE信息失败],{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String method = "INVITE";
|
||||
sipListener.addRequestProcessor(method, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
package com.fastbee.sip.handler.req;
|
||||
|
||||
import com.fastbee.common.utils.DateUtils;
|
||||
import com.fastbee.iot.domain.Device;
|
||||
import com.fastbee.iot.service.IDeviceService;
|
||||
import com.fastbee.sip.conf.SysSipConfig;
|
||||
import com.fastbee.sip.domain.SipConfig;
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.domain.SipDeviceChannel;
|
||||
import com.fastbee.sip.handler.IReqHandler;
|
||||
import com.fastbee.sip.model.SipDate;
|
||||
import com.fastbee.sip.server.IGBListener;
|
||||
import com.fastbee.sip.server.MessageInvoker;
|
||||
import com.fastbee.sip.service.IMqttService;
|
||||
import com.fastbee.sip.service.ISipConfigService;
|
||||
import com.fastbee.sip.service.ISipDeviceChannelService;
|
||||
import com.fastbee.sip.service.ISipDeviceService;
|
||||
import com.fastbee.sip.util.DigestAuthUtil;
|
||||
import gov.nist.javax.sip.address.AddressImpl;
|
||||
import gov.nist.javax.sip.address.SipUri;
|
||||
import gov.nist.javax.sip.header.Expires;
|
||||
import gov.nist.javax.sip.header.SIPDateHeader;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.header.*;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RegisterReqHandler extends ReqAbstractHandler implements InitializingBean, IReqHandler {
|
||||
|
||||
@Autowired
|
||||
private ISipDeviceService sipDeviceService;
|
||||
@Autowired
|
||||
private ISipDeviceChannelService sipDeviceChannelService;
|
||||
@Autowired
|
||||
private IDeviceService deviceService;
|
||||
|
||||
@Autowired
|
||||
private ISipConfigService sipConfigService;
|
||||
|
||||
@Autowired
|
||||
private IGBListener sipListener;
|
||||
|
||||
@Autowired
|
||||
private MessageInvoker messageInvoker;
|
||||
|
||||
@Autowired
|
||||
private SysSipConfig sysSipConfig;
|
||||
|
||||
@Autowired
|
||||
private IMqttService mqttService;
|
||||
|
||||
@Override
|
||||
public void processMsg(RequestEvent evt) {
|
||||
try {
|
||||
log.info("收到注册请求,开始处理");
|
||||
Request request = evt.getRequest();
|
||||
Response response;
|
||||
// 注册标志 0:未携带授权头或者密码错误 1:注册成功 2:注销成功
|
||||
int registerFlag;
|
||||
FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
|
||||
AddressImpl address = (AddressImpl) fromHeader.getAddress();
|
||||
SipUri uri = (SipUri) address.getURI();
|
||||
String sipId = uri.getUser();
|
||||
//取默认Sip配置
|
||||
SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(sipId);
|
||||
if (sipConfig != null) {
|
||||
AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
|
||||
// 校验密码是否正确
|
||||
if (authorhead == null && !ObjectUtils.isEmpty(sipConfig.getPassword())) {
|
||||
log.info("未携带授权头 回复401,sipId:"+ sipId);
|
||||
response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
|
||||
new DigestAuthUtil().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain());
|
||||
getServerTransaction(evt).sendResponse(response);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean pcheck = new DigestAuthUtil().doAuthenticatePlainTextPassword(request,
|
||||
sipConfig.getPassword());
|
||||
|
||||
boolean syscheck = new DigestAuthUtil().doAuthenticatePlainTextPassword(request,
|
||||
sysSipConfig.getPassword());
|
||||
if (!pcheck && !syscheck) {
|
||||
// 注册失败
|
||||
response = getMessageFactory().createResponse(Response.FORBIDDEN, request);
|
||||
response.setReasonPhrase("wrong password");
|
||||
log.info("[注册请求] 密码/SIP服务器ID错误, 回复403 sipId:" + sipId);
|
||||
getServerTransaction(evt).sendResponse(response);
|
||||
return;
|
||||
}
|
||||
response = getMessageFactory().createResponse(Response.OK, request);
|
||||
// 添加date头
|
||||
SIPDateHeader dateHeader = new SIPDateHeader();
|
||||
// 使用自己修改的
|
||||
SipDate sipDate = new SipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis());
|
||||
dateHeader.setDate(sipDate);
|
||||
response.addHeader(dateHeader);
|
||||
|
||||
ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME);
|
||||
// 添加Contact头
|
||||
response.addHeader(request.getHeader(ContactHeader.NAME));
|
||||
// 添加Expires头
|
||||
response.addHeader(request.getExpires());
|
||||
ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
|
||||
String received = viaHeader.getReceived();
|
||||
int rPort = viaHeader.getRPort();
|
||||
// 本地模拟设备 received 为空 rPort 为 -1
|
||||
// 解析本地地址替代
|
||||
if (StringUtils.isEmpty(received) || rPort == -1) {
|
||||
log.warn("本地地址替代! received:{},rPort:{} [{}:{}]", received, rPort, viaHeader.getHost(), viaHeader.getPort());
|
||||
received = viaHeader.getHost();
|
||||
rPort = viaHeader.getPort();
|
||||
}
|
||||
SipDevice device = new SipDevice();
|
||||
;
|
||||
device.setStreammode("UDP");
|
||||
device.setDeviceSipId(sipId);
|
||||
device.setIp(received);
|
||||
device.setPort(rPort);
|
||||
device.setHostaddress(received.concat(":").concat(String.valueOf(rPort)));
|
||||
// 注销成功
|
||||
if (expiresHeader != null && expiresHeader.getExpires() == 0) {
|
||||
registerFlag = 2;
|
||||
} else {
|
||||
registerFlag = 1;
|
||||
// 判断TCP还是UDP
|
||||
boolean isTcp = false;
|
||||
ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
|
||||
String transport = reqViaHeader.getTransport();
|
||||
if (transport.equals("TCP")) {
|
||||
isTcp = true;
|
||||
}
|
||||
device.setTransport(isTcp ? "TCP" : "UDP");
|
||||
}
|
||||
getServerTransaction(evt).sendResponse(response);
|
||||
// 注册成功
|
||||
if (registerFlag == 1) {
|
||||
log.info("注册成功! sipId:" + device.getDeviceSipId());
|
||||
device.setRegistertime(DateUtils.getNowDate());
|
||||
sipDeviceService.updateDevice(device);
|
||||
List<SipDeviceChannel> channels = sipDeviceChannelService.selectSipDeviceChannelByDeviceSipId(device.getDeviceSipId());
|
||||
if (channels.size() > 0) {
|
||||
Device iotdev = deviceService.selectDeviceBySerialNumber(device.getDeviceSipId());
|
||||
if (iotdev == null) {
|
||||
//添加到统一设备管理 默认添加到admin账号下
|
||||
int result = deviceService.insertDeviceAuto(device.getDeviceSipId(), 1L, sipConfig.getProductId());
|
||||
if (result == 1) {
|
||||
log.info("-----------sip设备认证成功,并自动添加设备到系统,SipId:" + device.getDeviceSipId() + "---------------");
|
||||
}
|
||||
iotdev = new Device();
|
||||
}
|
||||
if (iotdev.getStatus() != 3 && iotdev.getStatus() != 2) {
|
||||
iotdev.setStatus(3);
|
||||
deviceService.updateDeviceStatusAndLocation(iotdev,device.getIp());
|
||||
}
|
||||
// 重新注册更新设备和通道,以免设备替换或更新后信息无法更新
|
||||
onRegister(device);
|
||||
} else {
|
||||
log.info("未找到改设备! deviceId:" + device.getDeviceId());
|
||||
}
|
||||
} else if (registerFlag == 2) {
|
||||
log.info("注销成功! deviceId:" + device.getDeviceId());
|
||||
mqttService.publishStatus(device, 4);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void onRegister(SipDevice device) {
|
||||
// TODO 查询设备信息和下挂设备信息 自动拉流
|
||||
messageInvoker.deviceInfoQuery(device);
|
||||
messageInvoker.catalogQuery(device);
|
||||
messageInvoker.subscribe(device,0,0,3600,"0",null,null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String method = "REGISTER";
|
||||
sipListener.addRequestProcessor(method, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
package com.fastbee.sip.handler.req;
|
||||
|
||||
import gov.nist.javax.sip.SipStackImpl;
|
||||
import gov.nist.javax.sip.message.SIPRequest;
|
||||
import gov.nist.javax.sip.message.SIPResponse;
|
||||
import gov.nist.javax.sip.stack.SIPServerTransaction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import javax.sip.*;
|
||||
import javax.sip.header.FromHeader;
|
||||
import javax.sip.header.HeaderFactory;
|
||||
import javax.sip.header.ToHeader;
|
||||
import javax.sip.header.ViaHeader;
|
||||
import javax.sip.message.MessageFactory;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public abstract class ReqAbstractHandler {
|
||||
@Autowired
|
||||
@Qualifier(value = "udpSipServer")
|
||||
private SipProvider udpSipServer;
|
||||
|
||||
public ServerTransaction getServerTransaction(RequestEvent evt) {
|
||||
Request request = evt.getRequest();
|
||||
ServerTransaction serverTransaction = evt.getServerTransaction();
|
||||
// 判断TCP还是UDP
|
||||
boolean isTcp = false;
|
||||
ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
|
||||
String transport = reqViaHeader.getTransport();
|
||||
if (transport.equals("TCP")) {
|
||||
isTcp = true;
|
||||
}
|
||||
|
||||
if (serverTransaction == null) {
|
||||
try {
|
||||
if (!isTcp) {
|
||||
SipStackImpl stack = (SipStackImpl)udpSipServer.getSipStack();
|
||||
serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true);
|
||||
if (serverTransaction == null) {
|
||||
serverTransaction = udpSipServer.getNewServerTransaction(request);
|
||||
}
|
||||
}
|
||||
} catch (TransactionAlreadyExistsException | TransactionUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return serverTransaction;
|
||||
}
|
||||
|
||||
public HeaderFactory getHeaderFactory() {
|
||||
try {
|
||||
return SipFactory.getInstance().createHeaderFactory();
|
||||
} catch (PeerUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public MessageFactory getMessageFactory() {
|
||||
try {
|
||||
return SipFactory.getInstance().createMessageFactory();
|
||||
} catch (PeerUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void responseAck(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
|
||||
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
|
||||
getServerTransaction(evt).sendResponse(response);
|
||||
}
|
||||
|
||||
public SIPResponse responseAck(ServerTransaction serverTransaction, int statusCode) throws SipException, InvalidArgumentException, ParseException {
|
||||
return responseAck(serverTransaction, statusCode, null);
|
||||
}
|
||||
|
||||
public SIPResponse responseAck(ServerTransaction serverTransaction, int statusCode, String msg) throws SipException, InvalidArgumentException, ParseException {
|
||||
ToHeader toHeader = (ToHeader) serverTransaction.getRequest().getHeader(ToHeader.NAME);
|
||||
if (toHeader.getTag() == null) {
|
||||
toHeader.setTag(String.valueOf(System.currentTimeMillis()));
|
||||
}
|
||||
SIPResponse response = (SIPResponse)getMessageFactory().createResponse(statusCode, serverTransaction.getRequest());
|
||||
if (msg != null) {
|
||||
response.setReasonPhrase(msg);
|
||||
}
|
||||
serverTransaction.sendResponse(response);
|
||||
if (statusCode >= 200 && !"NOTIFY".equalsIgnoreCase(serverTransaction.getRequest().getMethod())) {
|
||||
if (serverTransaction.getDialog() != null) {
|
||||
serverTransaction.getDialog().delete();
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
public Element getRootElement(RequestEvent evt) throws DocumentException {
|
||||
return getRootElement(evt, "gb2312");
|
||||
}
|
||||
public Element getRootElement(RequestEvent evt, String charset) throws DocumentException {
|
||||
if (charset == null) {
|
||||
charset = "gb2312";
|
||||
}
|
||||
Request request = evt.getRequest();
|
||||
SAXReader reader = new SAXReader();
|
||||
reader.setEncoding(charset);
|
||||
// 对海康出现的未转义字符做处理。
|
||||
String[] destStrArray = new String[]{"<",">","&","'","""};
|
||||
char despChar = '&'; // 或许可扩展兼容其他字符
|
||||
byte destBye = (byte) despChar;
|
||||
List<Byte> result = new ArrayList<>();
|
||||
byte[] rawContent = request.getRawContent();
|
||||
if (rawContent == null) {
|
||||
FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
|
||||
log.error("rawContent is null,from:{} length:{}",fromHeader.toString(),request.getContentLength());
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < rawContent.length; i++) {
|
||||
if (rawContent[i] == destBye) {
|
||||
boolean resul = false;
|
||||
for (String destStr : destStrArray) {
|
||||
if (i + destStr.length() <= rawContent.length) {
|
||||
byte[] bytes = Arrays.copyOfRange(rawContent, i, i + destStr.length());
|
||||
resul = resul || (Arrays.equals(bytes,destStr.getBytes()));
|
||||
}
|
||||
}
|
||||
if (resul) {
|
||||
result.add(rawContent[i]);
|
||||
}
|
||||
} else {
|
||||
result.add(rawContent[i]);
|
||||
}
|
||||
}
|
||||
Byte[] bytes = new Byte[0];
|
||||
byte[] bytesResult = ArrayUtils.toPrimitive(result.toArray(bytes));
|
||||
String content = new String(bytesResult);
|
||||
//过滤掉非法字符
|
||||
String ret = XMLChars(content);
|
||||
Document xml = reader.read(new ByteArrayInputStream(bytesResult));
|
||||
return xml.getRootElement();
|
||||
|
||||
}
|
||||
public String XMLChars(String s) {
|
||||
if (s == null || "".equals(s)) {
|
||||
return s;
|
||||
}
|
||||
return s.replaceAll("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", "");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.fastbee.sip.handler.req;
|
||||
|
||||
import com.fastbee.sip.handler.IReqHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UnknowReqHandler extends ReqAbstractHandler implements IReqHandler {
|
||||
|
||||
@Override
|
||||
public void processMsg(RequestEvent evt) {
|
||||
log.warn("Unknow the method! Method:" + evt.getRequest().getMethod());
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.fastbee.sip.handler.req.message;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import org.dom4j.Element;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
public interface IMessageHandler {
|
||||
/**
|
||||
* 处理来自设备的信息
|
||||
* @param evt
|
||||
* @param device
|
||||
*/
|
||||
void handlerCmdType(RequestEvent evt, SipDevice device, Element element);
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.fastbee.sip.handler.req.message;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.util.XmlUtil;
|
||||
import org.dom4j.Element;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
public abstract class MessageHandlerAbstract implements IMessageHandler {
|
||||
public Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
|
||||
|
||||
public void addHandler(String cmdType, IMessageHandler messageHandler) {
|
||||
messageHandlerMap.put(cmdType, messageHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
String cmd = XmlUtil.getText(element, "CmdType");
|
||||
IMessageHandler messageHandler = messageHandlerMap.get(cmd);
|
||||
if (messageHandler != null) {
|
||||
messageHandler.handlerCmdType(evt, device, element);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package com.fastbee.sip.handler.req.message;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.IReqHandler;
|
||||
import com.fastbee.sip.handler.req.ReqAbstractHandler;
|
||||
import com.fastbee.sip.server.IGBListener;
|
||||
import com.fastbee.sip.service.ISipDeviceService;
|
||||
import com.fastbee.sip.util.SipUtil;
|
||||
import gov.nist.javax.sip.message.SIPRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.ServerTransaction;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.message.Response;
|
||||
import java.text.ParseException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MessageRequestProcessor extends ReqAbstractHandler implements InitializingBean, IReqHandler {
|
||||
@Autowired
|
||||
private IGBListener sipListener;
|
||||
|
||||
@Autowired
|
||||
private ISipDeviceService sipDeviceService;
|
||||
|
||||
private static Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
|
||||
|
||||
public void addHandler(String name, IMessageHandler handler) {
|
||||
messageHandlerMap.put(name, handler);
|
||||
}
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String method = "MESSAGE";
|
||||
sipListener.addRequestProcessor(method, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processMsg(RequestEvent evt) {
|
||||
SIPRequest sipRequest = (SIPRequest)evt.getRequest();
|
||||
String deviceId = SipUtil.getUserIdFromFromHeader(sipRequest);
|
||||
ServerTransaction serverTransaction = getServerTransaction(evt);
|
||||
// 查询设备是否存在
|
||||
SipDevice device = sipDeviceService.selectSipDeviceBySipId(deviceId);
|
||||
try {
|
||||
if (device == null ) {
|
||||
// 不存在则回复404
|
||||
responseAck(serverTransaction, Response.NOT_FOUND, "device "+ deviceId +" not found");
|
||||
log.warn("[设备未找到 ]: {}", deviceId);
|
||||
} else {
|
||||
Element rootElement = null;
|
||||
try {
|
||||
rootElement = getRootElement(evt);
|
||||
if (rootElement == null) {
|
||||
log.error("处理MESSAGE请求 未获取到消息体{}", evt.getRequest());
|
||||
responseAck(serverTransaction, Response.BAD_REQUEST, "content is null");
|
||||
return;
|
||||
}
|
||||
} catch (DocumentException e) {
|
||||
log.warn("解析XML消息内容异常", e);
|
||||
// 不存在则回复404
|
||||
responseAck(serverTransaction, Response.BAD_REQUEST, e.getMessage());
|
||||
}
|
||||
assert rootElement != null;
|
||||
String name = rootElement.getName();
|
||||
//log.debug("接收到消息:" + evt.getRequest());
|
||||
IMessageHandler messageHandler = messageHandlerMap.get(name);
|
||||
if ( messageHandler != null) {
|
||||
messageHandler.handlerCmdType(evt, device, rootElement);
|
||||
} else {
|
||||
// 不支持的message
|
||||
// 不存在则回复415
|
||||
responseAck(serverTransaction, Response.UNSUPPORTED_MEDIA_TYPE, "Unsupported message type, must Control/Notify/Query/Response");
|
||||
}
|
||||
}
|
||||
} catch (SipException e) {
|
||||
log.warn("SIP 回复错误", e);
|
||||
} catch (InvalidArgumentException e) {
|
||||
log.warn("参数无效", e);
|
||||
} catch (ParseException e) {
|
||||
log.warn("SIP回复时解析异常", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.fastbee.sip.handler.req.message.notify;
|
||||
|
||||
import com.fastbee.sip.handler.req.message.MessageHandlerAbstract;
|
||||
import com.fastbee.sip.handler.req.message.MessageRequestProcessor;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class NotifyMessageHandler extends MessageHandlerAbstract implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private MessageRequestProcessor messageRequestProcessor;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String messageType = "Notify";
|
||||
messageRequestProcessor.addHandler(messageType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.fastbee.sip.handler.req.message.notify.cmdType;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.notify.NotifyMessageHandler;
|
||||
import com.fastbee.sip.server.MessageInvoker;
|
||||
import com.fastbee.sip.server.SipMessage;
|
||||
import com.fastbee.sip.server.msg.Alarm;
|
||||
import com.fastbee.sip.service.IMqttService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AlarmHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private NotifyMessageHandler notifyMessageHandler;
|
||||
|
||||
@Autowired
|
||||
private MessageInvoker messageInvoker;
|
||||
|
||||
@Autowired
|
||||
private IMqttService mqttService;
|
||||
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
log.info("设备报警:{}", device.getDeviceId());
|
||||
SipMessage message = messageInvoker.messageToObj(evt);
|
||||
if (message instanceof Alarm) {
|
||||
log.info("报警内容:{}", message);
|
||||
mqttService.publishEvent((Alarm) message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "Alarm";
|
||||
notifyMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.fastbee.sip.handler.req.message.notify.cmdType;
|
||||
|
||||
import com.fastbee.common.utils.DateUtils;
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.ReqAbstractHandler;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.notify.NotifyMessageHandler;
|
||||
import com.fastbee.sip.server.MessageInvoker;
|
||||
import com.fastbee.sip.service.IMqttService;
|
||||
import com.fastbee.sip.service.ISipDeviceService;
|
||||
import com.fastbee.sip.util.XmlUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.header.ViaHeader;
|
||||
import java.text.ParseException;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class KeepaliveHandler extends ReqAbstractHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private NotifyMessageHandler notifyMessageHandler;
|
||||
|
||||
@Autowired
|
||||
private ISipDeviceService sipDeviceService;
|
||||
|
||||
@Autowired
|
||||
private MessageInvoker messageInvoker;
|
||||
|
||||
@Autowired
|
||||
private IMqttService mqttService;
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
try {
|
||||
Element rootElement = getRootElement(evt);
|
||||
String deviceId = XmlUtil.getText(rootElement, "DeviceID");
|
||||
if (sipDeviceService.exists(deviceId)) {
|
||||
ViaHeader viaHeader = (ViaHeader) evt.getRequest().getHeader(ViaHeader.NAME);
|
||||
String received = viaHeader.getReceived();
|
||||
int rPort = viaHeader.getRPort();
|
||||
if (StringUtils.isEmpty(received) || rPort == -1) {
|
||||
log.warn("本地地址替代! received:{},rPort:{} [{}:{}]", received, rPort, viaHeader.getHost(), viaHeader.getPort());
|
||||
received = viaHeader.getHost();
|
||||
rPort = viaHeader.getPort();
|
||||
}
|
||||
device.setLastconnecttime(DateUtils.getNowDate());
|
||||
device.setIp(received);
|
||||
device.setPort(rPort);
|
||||
device.setHostaddress(received.concat(":").concat(String.valueOf(rPort)));
|
||||
log.info("设备:{} 心跳上报时间:{}",deviceId,device.getLastconnecttime());
|
||||
//log.warn("设备:{} 心跳上报时间:{}",deviceId,device.getLastconnecttime());
|
||||
// 更新在线状态
|
||||
sipDeviceService.updateSipDeviceStatus(device);
|
||||
// 更新在线状态到emqx
|
||||
// mqttService.publishStatus(device, 3);
|
||||
// 更新通道状态
|
||||
messageInvoker.catalogQuery(device);
|
||||
// 回复200 OK
|
||||
responseAck(evt);
|
||||
}
|
||||
|
||||
} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "Keepalive";
|
||||
notifyMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.fastbee.sip.handler.req.message.notify.cmdType;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.notify.NotifyMessageHandler;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
public class MediaStatusHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private NotifyMessageHandler notifyMessageHandler;
|
||||
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "MediaStatus";
|
||||
notifyMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.fastbee.sip.handler.req.message.notify.cmdType;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.notify.NotifyMessageHandler;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
public class MobilePositionHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private NotifyMessageHandler notifyMessageHandler;
|
||||
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "MobilePosition";
|
||||
notifyMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.fastbee.sip.handler.req.message.response;
|
||||
|
||||
import com.fastbee.sip.handler.req.message.MessageHandlerAbstract;
|
||||
import com.fastbee.sip.handler.req.message.MessageRequestProcessor;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ResponseMessageHandler extends MessageHandlerAbstract implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private MessageRequestProcessor messageRequestProcessor;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String messageType = "Response";
|
||||
messageRequestProcessor.addHandler(messageType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.fastbee.sip.handler.req.message.response.cmdType;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.response.ResponseMessageHandler;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
@Component
|
||||
public class AlarmRHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private ResponseMessageHandler responseMessageHandler;
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "Alarm";
|
||||
responseMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
package com.fastbee.sip.handler.req.message.response.cmdType;
|
||||
|
||||
import com.fastbee.common.utils.DateUtils;
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.domain.SipDeviceChannel;
|
||||
import com.fastbee.sip.enums.ChannelType;
|
||||
import com.fastbee.sip.enums.DeviceChannelStatus;
|
||||
import com.fastbee.sip.handler.req.ReqAbstractHandler;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.response.ResponseMessageHandler;
|
||||
import com.fastbee.sip.service.ISipDeviceChannelService;
|
||||
import com.fastbee.sip.util.XmlUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.SipException;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CatalogHandler extends ReqAbstractHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private ResponseMessageHandler responseMessageHandler;
|
||||
|
||||
@Autowired
|
||||
private ISipDeviceChannelService sipDeviceChannelService;
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
try {
|
||||
Element rootElement = getRootElement(evt);
|
||||
Element deviceListElement = rootElement.element("DeviceList");
|
||||
if (deviceListElement == null) {
|
||||
return;
|
||||
}
|
||||
Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
|
||||
//List<SipDeviceChannel> channels = new ArrayList<>();
|
||||
if (deviceListIterator != null) {
|
||||
// 遍历DeviceList
|
||||
while (deviceListIterator.hasNext()) {
|
||||
SipDeviceChannel deviceChannel = new SipDeviceChannel();
|
||||
Element itemDevice = deviceListIterator.next();
|
||||
Element channelDeviceElement = itemDevice.element("DeviceID");
|
||||
if (channelDeviceElement == null) {
|
||||
log.warn("缺少 DeviceID");
|
||||
continue;
|
||||
}
|
||||
String channelId = channelDeviceElement.getTextTrim();
|
||||
if (ObjectUtils.isEmpty(channelId)) {
|
||||
log.warn("缺少 DeviceID");
|
||||
continue;
|
||||
}
|
||||
//Status
|
||||
Element statusElement = itemDevice.element("Status");
|
||||
if (statusElement != null) {
|
||||
String status = statusElement.getTextTrim().trim();
|
||||
if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) {
|
||||
deviceChannel.setStatus(DeviceChannelStatus.online.getValue());
|
||||
}
|
||||
if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
|
||||
deviceChannel.setStatus(DeviceChannelStatus.offline.getValue());
|
||||
}
|
||||
} else {
|
||||
deviceChannel.setStatus(DeviceChannelStatus.offline.getValue());
|
||||
}
|
||||
|
||||
ChannelType channelType = ChannelType.Other;
|
||||
if (channelId.length() <= 8) {
|
||||
channelType = ChannelType.CivilCode;
|
||||
deviceChannel.setHasaudio(0);
|
||||
}else {
|
||||
if (channelId.length() == 20) {
|
||||
int code = Integer.parseInt(channelId.substring(10, 13));
|
||||
switch (code){
|
||||
case 215:
|
||||
channelType = ChannelType.BusinessGroup;
|
||||
deviceChannel.setHasaudio(0);
|
||||
break;
|
||||
case 216:
|
||||
channelType = ChannelType.VirtualOrganization;
|
||||
deviceChannel.setHasaudio(0);
|
||||
break;
|
||||
case 136:
|
||||
case 137:
|
||||
case 138:
|
||||
deviceChannel.setHasaudio(1);
|
||||
break;
|
||||
default:
|
||||
deviceChannel.setHasaudio(0);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
deviceChannel.setDeviceSipId(device.getDeviceSipId());
|
||||
deviceChannel.setChannelSipId(channelId);
|
||||
|
||||
//name
|
||||
Element channdelNameElement = itemDevice.element("Name");
|
||||
String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim() : "";
|
||||
deviceChannel.setChannelName(channelName);
|
||||
//CivilCode
|
||||
String civilCode = XmlUtil.getText(itemDevice, "CivilCode");
|
||||
deviceChannel.setCivilcode(civilCode);
|
||||
if (channelType == ChannelType.CivilCode && civilCode == null) {
|
||||
deviceChannel.setParental(1);
|
||||
// 行政区划如果没有传递具体值,则推测一个
|
||||
if (channelId.length() > 2) {
|
||||
deviceChannel.setCivilcode(channelId.substring(0, channelId.length() - 2));
|
||||
}
|
||||
}
|
||||
if (channelType.equals(ChannelType.CivilCode)) {
|
||||
// 行政区划其他字段没必要识别了,默认在线即可
|
||||
deviceChannel.setStatus(1);
|
||||
deviceChannel.setParental(1);
|
||||
sipDeviceChannelService.updateChannel(device.getDeviceSipId(), deviceChannel);
|
||||
continue;
|
||||
}
|
||||
//parentID
|
||||
String parentId = XmlUtil.getText(itemDevice, "ParentID");
|
||||
//String businessGroupID = XmlUtil.getText(itemDevice, "BusinessGroupID");
|
||||
if (parentId != null) {
|
||||
if (parentId.contains("/")) {
|
||||
String lastParentId = parentId.substring(parentId.lastIndexOf("/") + 1);
|
||||
deviceChannel.setParentid(lastParentId);
|
||||
}else {
|
||||
deviceChannel.setParentid(parentId);
|
||||
}
|
||||
// 兼容设备通道信息中自己为自己父节点的情况
|
||||
if (deviceChannel.getParentid().equals(deviceChannel.getChannelSipId())) {
|
||||
deviceChannel.setParentid(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Parental
|
||||
String parental = XmlUtil.getText(itemDevice, "Parental");
|
||||
// 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
|
||||
if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
|
||||
deviceChannel.setParental(0);
|
||||
}else {
|
||||
deviceChannel.setParental(1);
|
||||
}
|
||||
|
||||
if (deviceChannel.getRegisterTime() == null) {
|
||||
deviceChannel.setRegisterTime(DateUtils.getNowDate());
|
||||
}
|
||||
deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
|
||||
deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
|
||||
deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
|
||||
deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
|
||||
deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
|
||||
deviceChannel.setIpaddress(XmlUtil.getText(itemDevice, "IPAddress"));
|
||||
if (XmlUtil.getText(itemDevice, "Port") == null || Objects.equals(XmlUtil.getText(itemDevice, "Port"), "")) {
|
||||
deviceChannel.setPort(0);
|
||||
} else {
|
||||
deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port")));
|
||||
}
|
||||
deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
|
||||
|
||||
if (XmlUtil.getText(itemDevice, "Longitude") == null || Objects.equals(XmlUtil.getText(itemDevice, "Longitude"), "")) {
|
||||
deviceChannel.setLongitude(BigDecimal.valueOf(0.00));
|
||||
} else {
|
||||
deviceChannel.setLongitude(BigDecimal.valueOf(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude"))));
|
||||
}
|
||||
if (XmlUtil.getText(itemDevice, "Latitude") == null || Objects.equals(XmlUtil.getText(itemDevice, "Latitude"), "")) {
|
||||
deviceChannel.setLatitude(BigDecimal.valueOf(0.00));
|
||||
} else {
|
||||
deviceChannel.setLatitude(BigDecimal.valueOf(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude"))));
|
||||
}
|
||||
|
||||
if (XmlUtil.getText(itemDevice, "PTZType") == null || "".equals(XmlUtil.getText(itemDevice, "PTZType"))) {
|
||||
//兼容INFO中的信息
|
||||
Element info = itemDevice.element("Info");
|
||||
if(XmlUtil.getText(info, "PTZType") == null || "".equals(XmlUtil.getText(info, "PTZType"))){
|
||||
deviceChannel.setPtztype(0L);
|
||||
} else {
|
||||
deviceChannel.setPtztype(Long.parseLong(XmlUtil.getText(info, "PTZType")));
|
||||
}
|
||||
} else {
|
||||
deviceChannel.setPtztype(Long.parseLong(XmlUtil.getText(itemDevice, "PTZType")));
|
||||
}
|
||||
|
||||
//更新到数据库
|
||||
sipDeviceChannelService.updateChannel(device.getDeviceSipId(), deviceChannel);
|
||||
//channels.add(deviceChannel);
|
||||
}
|
||||
// 发布设备property到emqx
|
||||
//mqttService.publishChannelsProperty(device.getDeviceSipId(),channels);
|
||||
// 回复200 OK
|
||||
responseAck(evt);
|
||||
}
|
||||
|
||||
} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "Catalog";
|
||||
responseMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.fastbee.sip.handler.req.message.response.cmdType;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.response.ResponseMessageHandler;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
@Component
|
||||
public class ConfigDownloadHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private ResponseMessageHandler responseMessageHandler;
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "ConfigDownload";
|
||||
responseMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.fastbee.sip.handler.req.message.response.cmdType;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.response.ResponseMessageHandler;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
@Component
|
||||
public class DeviceConfigHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private ResponseMessageHandler responseMessageHandler;
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "DeviceConfig";
|
||||
responseMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.fastbee.sip.handler.req.message.response.cmdType;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.response.ResponseMessageHandler;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
@Component
|
||||
public class DeviceControlHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private ResponseMessageHandler responseMessageHandler;
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "DeviceConfig";
|
||||
responseMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package com.fastbee.sip.handler.req.message.response.cmdType;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.ReqAbstractHandler;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.response.ResponseMessageHandler;
|
||||
import com.fastbee.sip.service.IMqttService;
|
||||
import com.fastbee.sip.service.ISipDeviceService;
|
||||
import com.fastbee.sip.util.XmlUtil;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.SipException;
|
||||
import java.text.ParseException;
|
||||
|
||||
@Component
|
||||
public class DeviceInfoHandler extends ReqAbstractHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private ResponseMessageHandler responseMessageHandler;
|
||||
|
||||
@Autowired
|
||||
private ISipDeviceService sipDeviceService;
|
||||
|
||||
@Autowired
|
||||
private IMqttService mqttService;
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
try {
|
||||
Element rootElement = getRootElement(evt);
|
||||
device.setDeviceName(XmlUtil.getText(rootElement, "DeviceName"));
|
||||
device.setManufacturer(XmlUtil.getText(rootElement, "Manufacturer"));
|
||||
device.setModel(XmlUtil.getText(rootElement, "Model"));
|
||||
device.setFirmware(XmlUtil.getText(rootElement, "Firmware"));
|
||||
if (StringUtils.isEmpty(device.getStreammode())) {
|
||||
device.setStreammode("UDP");
|
||||
}
|
||||
// 更新到数据库
|
||||
sipDeviceService.updateDevice(device);
|
||||
// 发布设备info到emqx
|
||||
mqttService.publishInfo(device);
|
||||
// 回复200 OK
|
||||
responseAck(evt);
|
||||
|
||||
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "DeviceInfo";
|
||||
responseMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.fastbee.sip.handler.req.message.response.cmdType;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.response.ResponseMessageHandler;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
@Component
|
||||
public class DeviceStatusHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private ResponseMessageHandler responseMessageHandler;
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "DeviceStatus";
|
||||
responseMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.fastbee.sip.handler.req.message.response.cmdType;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.response.ResponseMessageHandler;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
@Component
|
||||
public class MobilePositionRHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private ResponseMessageHandler responseMessageHandler;
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "MobilePosition";
|
||||
responseMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package com.fastbee.sip.handler.req.message.response.cmdType;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.handler.req.ReqAbstractHandler;
|
||||
import com.fastbee.sip.handler.req.message.IMessageHandler;
|
||||
import com.fastbee.sip.handler.req.message.response.ResponseMessageHandler;
|
||||
import com.fastbee.sip.model.RecordItem;
|
||||
import com.fastbee.sip.model.RecordList;
|
||||
import com.fastbee.sip.server.RecordCacheManager;
|
||||
import com.fastbee.sip.service.ISipCacheService;
|
||||
import com.fastbee.sip.util.SipUtil;
|
||||
import com.fastbee.sip.util.XmlUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.RequestEvent;
|
||||
import javax.sip.SipException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RecordInfoHandler extends ReqAbstractHandler implements InitializingBean, IMessageHandler {
|
||||
|
||||
@Autowired
|
||||
private ResponseMessageHandler responseMessageHandler;
|
||||
|
||||
@Autowired
|
||||
private ISipCacheService sipCacheService;
|
||||
|
||||
@Autowired
|
||||
private RecordCacheManager recordCacheManager;
|
||||
@Override
|
||||
public void handlerCmdType(RequestEvent evt, SipDevice device, Element element) {
|
||||
try {
|
||||
// 回复200 OK
|
||||
responseAck(evt);
|
||||
Element rootElement = getRootElement(evt);
|
||||
String deviceId = rootElement.element("DeviceID").getText();
|
||||
String sn = XmlUtil.getText(rootElement, "SN");
|
||||
String sumNum = XmlUtil.getText(rootElement, "SumNum");
|
||||
String recordkey = deviceId + ":" + sn;
|
||||
int recordnum = 0;
|
||||
RecordList recordList = recordCacheManager.get(recordkey);
|
||||
recordList.setDeviceID(deviceId);
|
||||
Element recordListElement = rootElement.element("RecordList");
|
||||
if (recordListElement == null || sumNum == null || sumNum.equals("")) {
|
||||
log.info("无录像数据");
|
||||
} else {
|
||||
Iterator<Element> recordListIterator = recordListElement.elementIterator();
|
||||
if (recordListIterator != null) {
|
||||
while (recordListIterator.hasNext()) {
|
||||
Element itemRecord = recordListIterator.next();
|
||||
Element recordElement = itemRecord.element("DeviceID");
|
||||
if (recordElement == null) {
|
||||
continue;
|
||||
}
|
||||
RecordItem item = new RecordItem();
|
||||
item.setStart(SipUtil.ISO8601Totimestamp(XmlUtil.getText(itemRecord, "StartTime")));
|
||||
item.setEnd(SipUtil.ISO8601Totimestamp(XmlUtil.getText(itemRecord, "EndTime")));
|
||||
recordList.addItem(item);
|
||||
recordnum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("getSumNum:{}", recordList.getSumNum());
|
||||
if (recordList.getSumNum() + recordnum == Integer.parseInt(sumNum)) {
|
||||
//时间合并 保存到redia
|
||||
recordList.mergeItems();
|
||||
log.info("mergeItems recordList:{}", recordList);
|
||||
recordCacheManager.remove(recordkey);
|
||||
sipCacheService.setRecordList(recordkey, recordList);
|
||||
//发布设备property到emqx
|
||||
} else {
|
||||
recordList.setSumNum(recordList.getSumNum() + recordnum);
|
||||
recordCacheManager.put(recordkey, recordList);
|
||||
}
|
||||
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String cmdType = "RecordInfo";
|
||||
responseMessageHandler.addHandler(cmdType, this);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.fastbee.sip.handler.res;
|
||||
|
||||
import com.fastbee.sip.handler.IResHandler;
|
||||
import com.fastbee.sip.server.IGBListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.ResponseEvent;
|
||||
import java.text.ParseException;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ByeResHandler implements InitializingBean,IResHandler {
|
||||
@Autowired
|
||||
private IGBListener sipListener;
|
||||
|
||||
@Override
|
||||
public void processMsg(ResponseEvent evt) throws ParseException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String method = "BYE";
|
||||
sipListener.addResponseProcessor(method,this);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.fastbee.sip.handler.res;
|
||||
|
||||
import com.fastbee.sip.handler.IResHandler;
|
||||
import com.fastbee.sip.server.IGBListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.ResponseEvent;
|
||||
import java.text.ParseException;
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CancelResHandler implements InitializingBean,IResHandler {
|
||||
@Autowired
|
||||
private IGBListener sipListener;
|
||||
|
||||
@Override
|
||||
public void processMsg(ResponseEvent evt) throws ParseException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String method = "CANCEL";
|
||||
sipListener.addResponseProcessor(method,this);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.fastbee.sip.handler.res;
|
||||
|
||||
import com.fastbee.sip.handler.IResHandler;
|
||||
import com.fastbee.sip.server.IGBListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.Dialog;
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.ResponseEvent;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.address.SipURI;
|
||||
import javax.sip.header.CSeqHeader;
|
||||
import javax.sip.header.ViaHeader;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
import java.text.ParseException;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class InviteResHandler implements InitializingBean,IResHandler {
|
||||
|
||||
@Autowired
|
||||
private IGBListener sipListener;
|
||||
|
||||
@Override
|
||||
public void processMsg(ResponseEvent evt) throws ParseException {
|
||||
Response response = evt.getResponse();
|
||||
Dialog dialog = evt.getDialog();
|
||||
CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
|
||||
Request reqAck = null;
|
||||
try {
|
||||
reqAck = dialog.createAck(cseq.getSeqNumber());
|
||||
SipURI requestURI = (SipURI) reqAck.getRequestURI();
|
||||
ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME);
|
||||
requestURI.setHost(viaHeader.getHost());
|
||||
requestURI.setPort(viaHeader.getPort());
|
||||
reqAck.setRequestURI(requestURI);
|
||||
dialog.sendAck(reqAck);
|
||||
} catch (InvalidArgumentException | SipException | ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String method = "INVITE";
|
||||
sipListener.addResponseProcessor(method,this);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.fastbee.sip.handler.res;
|
||||
|
||||
import com.fastbee.sip.handler.IResHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.ResponseEvent;
|
||||
import java.text.ParseException;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UnknowResHandler implements IResHandler {
|
||||
@Override
|
||||
public void processMsg(ResponseEvent evt) throws ParseException {
|
||||
log.warn("Unknow Response! ReasonPhrase:" + evt.getResponse().getReasonPhrase());
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.fastbee.sip.mapper;
|
||||
|
||||
import com.fastbee.sip.domain.MediaServer;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流媒体服务器配置Mapper接口
|
||||
*
|
||||
* @author zhuangpeng.li
|
||||
* @date 2022-11-30
|
||||
*/
|
||||
@Repository
|
||||
public interface MediaServerMapper
|
||||
{
|
||||
public MediaServer selectMediaServerById(Long id);
|
||||
/**
|
||||
* 查询流媒体服务器配置
|
||||
*
|
||||
* @return 流媒体服务器配置
|
||||
*/
|
||||
public List<MediaServer> selectMediaServer(MediaServer mediaServer);
|
||||
public List<MediaServer> selectMediaServerBytenantId(Long tenantId);
|
||||
/**
|
||||
* 查询流媒体服务器配置列表
|
||||
*
|
||||
* @param mediaServer 流媒体服务器配置
|
||||
* @return 流媒体服务器配置集合
|
||||
*/
|
||||
public List<MediaServer> selectMediaServerList(MediaServer mediaServer);
|
||||
|
||||
/**
|
||||
* 新增流媒体服务器配置
|
||||
*
|
||||
* @param mediaServer 流媒体服务器配置
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertMediaServer(MediaServer mediaServer);
|
||||
|
||||
/**
|
||||
* 修改流媒体服务器配置
|
||||
*
|
||||
* @param mediaServer 流媒体服务器配置
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateMediaServer(MediaServer mediaServer);
|
||||
|
||||
/**
|
||||
* 删除流媒体服务器配置
|
||||
*
|
||||
* @param id 流媒体服务器配置主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteMediaServerById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除流媒体服务器配置
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteMediaServerByIds(Long[] ids);
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.fastbee.sip.mapper;
|
||||
|
||||
import com.fastbee.sip.domain.SipConfig;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* sip系统配置Mapper接口
|
||||
*
|
||||
* @author zhuangpeng.li
|
||||
* @date 2022-11-30
|
||||
*/
|
||||
@Repository
|
||||
public interface SipConfigMapper
|
||||
{
|
||||
/**
|
||||
* 查询产品下第一条sip系统配置
|
||||
*
|
||||
* @return sip系统配置
|
||||
*/
|
||||
public SipConfig selectSipConfigByProductId(Long productId);
|
||||
/**
|
||||
* 查询sip系统配置列表
|
||||
*
|
||||
* @param sipConfig sip系统配置
|
||||
* @return sip系统配置集合
|
||||
*/
|
||||
public List<SipConfig> selectSipConfigList(SipConfig sipConfig);
|
||||
|
||||
/**
|
||||
* 新增sip系统配置
|
||||
*
|
||||
* @param sipConfig sip系统配置
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSipConfig(SipConfig sipConfig);
|
||||
|
||||
/**
|
||||
* 修改sip系统配置
|
||||
*
|
||||
* @param sipConfig sip系统配置
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSipConfig(SipConfig sipConfig);
|
||||
|
||||
public int resetDefaultSipConfig();
|
||||
|
||||
/**
|
||||
* 删除sip系统配置
|
||||
*
|
||||
* @param id sip系统配置主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSipConfigById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除sip系统配置
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSipConfigByIds(Long[] ids);
|
||||
|
||||
public int deleteSipConfigByProductId(Long[] productIds);
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package com.fastbee.sip.mapper;
|
||||
|
||||
import com.fastbee.common.core.domain.AjaxResult;
|
||||
import com.fastbee.sip.domain.BindingChannel;
|
||||
import com.fastbee.sip.domain.SipDeviceChannel;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 监控设备通道信息Mapper接口
|
||||
*
|
||||
* @author zhuangpeng.li
|
||||
* @date 2022-10-07
|
||||
*/
|
||||
@Repository
|
||||
public interface SipDeviceChannelMapper {
|
||||
/**
|
||||
* 查询监控设备通道信息
|
||||
*
|
||||
* @param channelId 监控设备通道信息主键
|
||||
* @return 监控设备通道信息
|
||||
*/
|
||||
public SipDeviceChannel selectSipDeviceChannelById(Long channelId);
|
||||
|
||||
public SipDeviceChannel selectSipDeviceChannelByChannelSipId(String channelSipId);
|
||||
|
||||
public List<SipDeviceChannel> selectSipDeviceChannelByDeviceSipId(String deviceSipId);
|
||||
|
||||
/**
|
||||
* 查询监控设备通道信息列表
|
||||
*
|
||||
* @param sipDeviceChannel 监控设备通道信息
|
||||
* @return 监控设备通道信息集合
|
||||
*/
|
||||
public List<SipDeviceChannel> selectSipDeviceChannelList(SipDeviceChannel sipDeviceChannel);
|
||||
List<SipDeviceChannel> selectChannelWithCivilCodeAndLength(@Param("deviceSipId") String deviceSipId, @Param("parentId") String parentId, @Param("length")Integer length);
|
||||
|
||||
public List<SipDeviceChannel> selectChannelByCivilCode(@Param("deviceSipId") String deviceSipId, @Param("parentId") String parentId);
|
||||
List<SipDeviceChannel> selectChannelWithoutCiviCode(String deviceId);
|
||||
Integer getChannelMinLength(String deviceSipId);
|
||||
/**
|
||||
* 新增监控设备通道信息
|
||||
*
|
||||
* @param sipDeviceChannel 监控设备通道信息
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSipDeviceChannel(SipDeviceChannel sipDeviceChannel);
|
||||
|
||||
/**
|
||||
* 修改监控设备通道信息
|
||||
*
|
||||
* @param sipDeviceChannel 监控设备通道信息
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSipDeviceChannel(SipDeviceChannel sipDeviceChannel);
|
||||
|
||||
public int updateChannelStreamId(SipDeviceChannel sipDeviceChannel);
|
||||
|
||||
/**
|
||||
* 删除监控设备通道信息
|
||||
*
|
||||
* @param channelId 监控设备通道信息主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSipDeviceChannelById(Long channelId);
|
||||
|
||||
/**
|
||||
* 批量删除监控设备通道信息
|
||||
*
|
||||
* @param channelIds 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSipDeviceChannelByIds(Long[] channelIds);
|
||||
|
||||
public int deleteSipDeviceChannelByDeviceId(String deviceSipId);
|
||||
|
||||
/**
|
||||
* 根据channelId获取绑定的设备或场景
|
||||
* @param channelId
|
||||
* @return
|
||||
*/
|
||||
public BindingChannel getBindingChannel(String channelId);
|
||||
|
||||
/**
|
||||
* @description: 查询设备关联通道
|
||||
* @param: serialNumber 设备编号
|
||||
* @return: java.util.List<com.fastbee.sip.domain.SipDeviceChannel>
|
||||
*/
|
||||
List<SipDeviceChannel> selectDeviceRelSipDeviceChannelList(String serialNumber);
|
||||
|
||||
/**
|
||||
* @description: 查询场景关联通道
|
||||
* @param: sceneModelId 场景id
|
||||
* @return: java.util.List<com.fastbee.sip.domain.SipDeviceChannel>
|
||||
*/
|
||||
List<SipDeviceChannel> selectSceneRelSipDeviceChannelList(Long sceneModelId);
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.fastbee.sip.mapper;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 监控设备Mapper接口
|
||||
*
|
||||
* @author zhuangpeng.li
|
||||
* @date 2022-10-07
|
||||
*/
|
||||
@Repository
|
||||
public interface SipDeviceMapper
|
||||
{
|
||||
/**
|
||||
* 查询监控设备
|
||||
*
|
||||
* @param deviceId 监控设备主键
|
||||
* @return 监控设备
|
||||
*/
|
||||
public SipDevice selectSipDeviceByDeviceId(Long deviceId);
|
||||
|
||||
|
||||
public SipDevice selectSipDeviceBySipId(String sipId);
|
||||
/**
|
||||
* 查询监控设备列表
|
||||
*
|
||||
* @param sipDevice 监控设备
|
||||
* @return 监控设备集合
|
||||
*/
|
||||
public List<SipDevice> selectSipDeviceList(SipDevice sipDevice);
|
||||
public List<SipDevice> selectOfflineSipDevice(Integer timeout);
|
||||
|
||||
/**
|
||||
* 新增监控设备
|
||||
*
|
||||
* @param sipDevice 监控设备
|
||||
* @return 结果
|
||||
*/
|
||||
int insertSipDevice(SipDevice sipDevice);
|
||||
|
||||
/**
|
||||
* 修改监控设备
|
||||
*
|
||||
* @param sipDevice 监控设备
|
||||
* @return 结果
|
||||
*/
|
||||
int updateSipDevice(SipDevice sipDevice);
|
||||
|
||||
/**
|
||||
* 更新设备状态
|
||||
*
|
||||
* @param sipDevice 设备
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSipDeviceStatus(SipDevice sipDevice);
|
||||
|
||||
/**
|
||||
* 删除监控设备
|
||||
*
|
||||
* @param deviceId 监控设备主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSipDeviceByDeviceId(Long deviceId);
|
||||
|
||||
/**
|
||||
* 批量删除监控设备
|
||||
*
|
||||
* @param deviceIds 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSipDeviceByDeviceIds(Long[] deviceIds);
|
||||
|
||||
public int deleteSipDeviceByByDeviceSipId(String deviceSipId);
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.text.Collator;
|
||||
import java.util.Comparator;
|
||||
@Data
|
||||
public class BaseTree<T> implements Comparable<BaseTree>{
|
||||
private String id;
|
||||
private String deviceId;
|
||||
private String pid;
|
||||
private String name;
|
||||
private boolean parent;
|
||||
private T basicData;
|
||||
@Override
|
||||
public int compareTo(@NotNull BaseTree treeNode) {
|
||||
if (this.parent || treeNode.isParent()) {
|
||||
if (!this.parent && !treeNode.isParent()) {
|
||||
Comparator<Object> cmp = Collator.getInstance(java.util.Locale.CHINA);
|
||||
return cmp.compare(treeNode.getName(), this.getName());
|
||||
}else {
|
||||
if (this.isParent()) {
|
||||
return 1;
|
||||
}else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
Comparator<Object> cmp = Collator.getInstance(java.util.Locale.CHINA);
|
||||
return cmp.compare(treeNode.getName(), this.getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import com.fastbee.sip.enums.ChannelStatus;
|
||||
import com.fastbee.sip.enums.PTZType;
|
||||
import com.fastbee.sip.util.SipUtil;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
@Data
|
||||
public class GB28181DeviceChannel {
|
||||
/**
|
||||
* 通道对应的设备ID
|
||||
*/
|
||||
@JsonIgnore
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 通道类型
|
||||
*/
|
||||
@JacksonXmlProperty(isAttribute = true, localName = "itemType")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 通道id
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "DeviceID")
|
||||
private String channelId;
|
||||
|
||||
/**
|
||||
* 通道名
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Name")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 生产厂商
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Manufacturer")
|
||||
private String manufacturer;
|
||||
|
||||
/**
|
||||
* 型号
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Model")
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 设备归属
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Owner")
|
||||
private String owner;
|
||||
|
||||
/**
|
||||
* 行政区域
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "CivilCode")
|
||||
private String civilCode;
|
||||
|
||||
/**
|
||||
* 警区
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Block")
|
||||
private String block;
|
||||
|
||||
/**
|
||||
* 安装地址
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Address")
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* 是否有子设备 1有, 0没有
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Parental")
|
||||
private int parental;
|
||||
|
||||
/**
|
||||
* 父级id
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "ParentID")
|
||||
private String parentId;
|
||||
|
||||
/**
|
||||
* 信令安全模式 缺省为0; 0:不采用; 2: S/MIME签名方式; 3: S/ MIME加密签名同时采用方式; 4:数字摘要方式
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "SafetyWay")
|
||||
private int safetyWay;
|
||||
|
||||
/**
|
||||
* 注册方式 缺省为1;1:符合IETF RFC3261标准的认证注册模 式; 2:基于口令的双向认证注册模式; 3:基于数字证书的双向认证注册模式
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "RegisterWay")
|
||||
private String registerWay;
|
||||
|
||||
/**
|
||||
* 证书序列号
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "CertNum")
|
||||
private String certNum;
|
||||
|
||||
/**
|
||||
* 证书有效标识 缺省为0;证书有效标识:0:无效1: 有效
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Certifiable")
|
||||
private int certifiable;
|
||||
|
||||
/**
|
||||
* 证书无效原因码
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "ErrCode")
|
||||
private int errCode;
|
||||
|
||||
/**
|
||||
* 证书终止有效期
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "EndTime")
|
||||
private String endTime;
|
||||
|
||||
/**
|
||||
* 保密属性 缺省为0; 0:不涉密, 1:涉密
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Secrecy")
|
||||
private String secrecy;
|
||||
|
||||
/**
|
||||
* IP地址
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "IpAddress")
|
||||
private String ipAddress;
|
||||
|
||||
/**
|
||||
* 端口号
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Port")
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Password")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 详情信息
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Info")
|
||||
private Info info;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Longitude")
|
||||
private double longitude;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "Latitude")
|
||||
private double latitude;
|
||||
|
||||
/**
|
||||
* 子设备数
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "SubCount")
|
||||
private int subCount;
|
||||
|
||||
@JacksonXmlProperty(localName = "Status")
|
||||
private ChannelStatus status;
|
||||
|
||||
//目录类型: 0目录,1设备通道?
|
||||
@JacksonXmlProperty(localName = "CatalogType")
|
||||
private String catalogType;
|
||||
|
||||
@JacksonXmlProperty(localName = "Event")
|
||||
private String event;
|
||||
|
||||
@JacksonXmlProperty(localName = "BusinessGroupID")
|
||||
private String businessGroupId;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class Info {
|
||||
|
||||
/**
|
||||
* 云台类型
|
||||
*/
|
||||
@JacksonXmlProperty(localName = "PTZType")
|
||||
private PTZType PTZType;
|
||||
|
||||
@JacksonXmlProperty(localName = "DownloadSpeed")
|
||||
private String downloadSpeed;
|
||||
|
||||
public String toXML() {
|
||||
StringJoiner joiner = new StringJoiner("");
|
||||
joiner
|
||||
.add("<PTZType>")
|
||||
.add(PTZType == null ? "0" : String.valueOf(getPTZType().getValue()))
|
||||
.add("</PTZType>\n");
|
||||
joiner.add("<DownloadSpeed>").add(SipUtil.safeString(downloadSpeed)).add("</DownloadSpeed>\n");
|
||||
|
||||
return joiner.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class InviteInfo {
|
||||
private String ssrc;
|
||||
private String callId;
|
||||
private String fromTag;
|
||||
private String viaTag;
|
||||
private int port;
|
||||
}
|
@ -0,0 +1,203 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MediaServerConfig {
|
||||
@JSONField(name = "api.apiDebug")
|
||||
private String apiDebug;
|
||||
|
||||
@JSONField(name = "api.secret")
|
||||
private String apiSecret;
|
||||
|
||||
@JSONField(name = "ffmpeg.bin")
|
||||
private String ffmpegBin;
|
||||
|
||||
@JSONField(name = "ffmpeg.cmd")
|
||||
private String ffmpegCmd;
|
||||
|
||||
@JSONField(name = "ffmpeg.log")
|
||||
private String ffmpegLog;
|
||||
|
||||
@JSONField(name = "general.enableVhost")
|
||||
private String generalEnableVhost;
|
||||
|
||||
@JSONField(name = "general.flowThreshold")
|
||||
private String generalFlowThreshold;
|
||||
|
||||
@JSONField(name = "general.maxStreamWaitMS")
|
||||
private String generalMaxStreamWaitMS;
|
||||
|
||||
@JSONField(name = "general.streamNoneReaderDelayMS")
|
||||
private String generalStreamNoneReaderDelayMS;
|
||||
|
||||
private String localIP;
|
||||
|
||||
private String wanIp;
|
||||
|
||||
@JSONField(name = "hls.fileBufSize")
|
||||
private String hlsFileBufSize;
|
||||
|
||||
@JSONField(name = "hls.filePath")
|
||||
private String hlsFilePath;
|
||||
|
||||
@JSONField(name = "hls.segDur")
|
||||
private String hlsSegDur;
|
||||
|
||||
@JSONField(name = "hls.segNum")
|
||||
private String hlsSegNum;
|
||||
|
||||
@JSONField(name = "hook.access_file_except_hls")
|
||||
private String hookAccessFileExceptHLS;
|
||||
|
||||
@JSONField(name = "hook.admin_params")
|
||||
private String hookAdminParams;
|
||||
|
||||
@JSONField(name = "hook.enable")
|
||||
private String hookEnable;
|
||||
|
||||
@JSONField(name = "hook.on_flow_report")
|
||||
private String hookOnFlowReport;
|
||||
|
||||
@JSONField(name = "hook.on_http_access")
|
||||
private String hookOnHttpAccess;
|
||||
|
||||
@JSONField(name = "hook.on_play")
|
||||
private String hookOnPlay;
|
||||
|
||||
@JSONField(name = "hook.on_publish")
|
||||
private String hookOnPublish;
|
||||
|
||||
@JSONField(name = "hook.on_record_mp4")
|
||||
private String hookOnRecordMp4;
|
||||
|
||||
@JSONField(name = "hook.on_rtsp_auth")
|
||||
private String hookOnRtspAuth;
|
||||
|
||||
@JSONField(name = "hook.on_rtsp_realm")
|
||||
private String hookOnRtspRealm;
|
||||
|
||||
@JSONField(name = "hook.on_shell_login")
|
||||
private String hookOnShellLogin;
|
||||
|
||||
@JSONField(name = "hook.on_stream_changed")
|
||||
private String hookOnStreamChanged;
|
||||
|
||||
@JSONField(name = "hook.on_stream_none_reader")
|
||||
private String hookOnStreamNoneReader;
|
||||
|
||||
@JSONField(name = "hook.on_stream_not_found")
|
||||
private String hookOnStreamNotFound;
|
||||
|
||||
@JSONField(name = "hook.timeoutSec")
|
||||
private String hookTimeoutSec;
|
||||
|
||||
@JSONField(name = "http.charSet")
|
||||
private String httpCharSet;
|
||||
|
||||
@JSONField(name = "http.keepAliveSecond")
|
||||
private String httpKeepAliveSecond;
|
||||
|
||||
@JSONField(name = "http.maxReqCount")
|
||||
private String httpMaxReqCount;
|
||||
|
||||
@JSONField(name = "http.maxReqSize")
|
||||
private String httpMaxReqSize;
|
||||
|
||||
@JSONField(name = "http.notFound")
|
||||
private String httpNotFound;
|
||||
|
||||
@JSONField(name = "http.port")
|
||||
private String httpPort;
|
||||
|
||||
@JSONField(name = "http.rootPath")
|
||||
private String httpRootPath;
|
||||
|
||||
@JSONField(name = "http.sendBufSize")
|
||||
private String httpSendBufSize;
|
||||
|
||||
@JSONField(name = "http.sslport")
|
||||
private String httpSSLport;
|
||||
|
||||
@JSONField(name = "multicast.addrMax")
|
||||
private String multicastAddrMax;
|
||||
|
||||
@JSONField(name = "multicast.addrMin")
|
||||
private String multicastAddrMin;
|
||||
|
||||
@JSONField(name = "multicast.udpTTL")
|
||||
private String multicastUdpTTL;
|
||||
|
||||
@JSONField(name = "record.appName")
|
||||
private String recordAppName;
|
||||
|
||||
@JSONField(name = "record.filePath")
|
||||
private String recordFilePath;
|
||||
|
||||
@JSONField(name = "record.fileSecond")
|
||||
private String recordFileSecond;
|
||||
|
||||
@JSONField(name = "record.sampleMS")
|
||||
private String recordFileSampleMS;
|
||||
|
||||
@JSONField(name = "rtmp.handshakeSecond")
|
||||
private String rtmpHandshakeSecond;
|
||||
|
||||
@JSONField(name = "rtmp.keepAliveSecond")
|
||||
private String rtmpKeepAliveSecond;
|
||||
|
||||
@JSONField(name = "rtmp.modifyStamp")
|
||||
private String rtmpModifyStamp;
|
||||
|
||||
@JSONField(name = "rtmp.port")
|
||||
private String rtmpPort;
|
||||
|
||||
@JSONField(name = "rtp.audioMtuSize")
|
||||
private String rtpAudioMtuSize;
|
||||
|
||||
@JSONField(name = "rtp.clearCount")
|
||||
private String rtpClearCount;
|
||||
|
||||
@JSONField(name = "rtp.cycleMS")
|
||||
private String rtpCycleMS;
|
||||
|
||||
@JSONField(name = "rtp.maxRtpCount")
|
||||
private String rtpMaxRtpCount;
|
||||
|
||||
@JSONField(name = "rtp.videoMtuSize")
|
||||
private String rtpVideoMtuSize;
|
||||
|
||||
@JSONField(name = "rtp_proxy.checkSource")
|
||||
private String rtpProxyCheckSource;
|
||||
|
||||
@JSONField(name = "rtp_proxy.dumpDir")
|
||||
private String rtpProxyDumpDir;
|
||||
|
||||
@JSONField(name = "rtp_proxy.port")
|
||||
private String rtpProxyPort;
|
||||
|
||||
@JSONField(name = "rtp_proxy.timeoutSec")
|
||||
private String rtpProxyTimeoutSec;
|
||||
|
||||
@JSONField(name = "rtsp.authBasic")
|
||||
private String rtspAuthBasic;
|
||||
|
||||
@JSONField(name = "rtsp.handshakeSecond")
|
||||
private String rtspHandshakeSecond;
|
||||
|
||||
@JSONField(name = "rtsp.keepAliveSecond")
|
||||
private String rtspKeepAliveSecond;
|
||||
|
||||
@JSONField(name = "rtsp.port")
|
||||
private String rtspPort;
|
||||
|
||||
@JSONField(name = "rtsp.sslport")
|
||||
private String rtspSSlport;
|
||||
|
||||
@JSONField(name = "shell.maxReqSize")
|
||||
private String shellMaxReqSize;
|
||||
|
||||
@JSONField(name = "shell.shell")
|
||||
private String shellPhell;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PtzDirectionInput {
|
||||
int leftRight;
|
||||
int upDown;
|
||||
int moveSpeed;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PtzscaleInput{
|
||||
int inOut;
|
||||
int scaleSpeed;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RecordInput {
|
||||
String deviceId;
|
||||
String channelId;
|
||||
String startTime;
|
||||
String endTime;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class RecordItem implements Comparable<RecordItem>{
|
||||
long start;
|
||||
long end;
|
||||
@Override
|
||||
public int compareTo(RecordItem item) {
|
||||
Date startTime_now = new Date(start*1000);
|
||||
Date startTime_param = new Date(item.getStart()*1000);
|
||||
if (startTime_param.compareTo(startTime_now) > 0) {
|
||||
return -1;
|
||||
}else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RecordList {
|
||||
String deviceID;
|
||||
int sumNum;
|
||||
private List<RecordItem> recordItems = new ArrayList<>();
|
||||
|
||||
public void addItem(RecordItem item) {
|
||||
this.recordItems.add(item);
|
||||
}
|
||||
|
||||
public void mergeItems() {
|
||||
recordItems.sort(Comparator.naturalOrder());
|
||||
List<RecordItem> temp = new ArrayList<>();
|
||||
long start = 0;
|
||||
long end = 0;
|
||||
for (int i = 0; i < recordItems.size(); i++) {
|
||||
RecordItem item = recordItems.get(i);
|
||||
if (i == recordItems.size() - 1) {
|
||||
if (end >= item.getStart()) {
|
||||
RecordItem titem = new RecordItem();
|
||||
titem.setStart(start);
|
||||
titem.setEnd(item.getEnd());
|
||||
temp.add(titem);
|
||||
} else {
|
||||
RecordItem titem = new RecordItem();
|
||||
titem.setStart(start);
|
||||
titem.setEnd(end);
|
||||
temp.add(titem);
|
||||
temp.add(item);
|
||||
}
|
||||
}
|
||||
if (start == 0 && end == 0) {
|
||||
start = item.getStart();
|
||||
end = item.getEnd();
|
||||
} else if (end >= item.getStart()) {
|
||||
end = item.getEnd();
|
||||
} else {
|
||||
RecordItem titem = new RecordItem();
|
||||
titem.setStart(start);
|
||||
titem.setEnd(end);
|
||||
temp.add(titem);
|
||||
start = item.getStart();
|
||||
end = item.getEnd();
|
||||
}
|
||||
}
|
||||
this.recordItems = temp;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RequestMessage {
|
||||
private String id;
|
||||
private String deviceId;
|
||||
private String type;
|
||||
private Object data;
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import gov.nist.core.InternalErrorHandler;
|
||||
import gov.nist.javax.sip.header.SIPDate;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SipDate extends SIPDate {
|
||||
|
||||
private final Calendar javaCal;
|
||||
|
||||
public SipDate(long timeMillis) {
|
||||
this.javaCal = new GregorianCalendar(TimeZone.getDefault(), Locale.getDefault());
|
||||
Date date = new Date(timeMillis);
|
||||
this.javaCal.setTime(date);
|
||||
this.wkday = this.javaCal.get(Calendar.DAY_OF_WEEK);
|
||||
switch(this.wkday) {
|
||||
case 1:
|
||||
this.sipWkDay = "Sun";
|
||||
break;
|
||||
case 2:
|
||||
this.sipWkDay = "Mon";
|
||||
break;
|
||||
case 3:
|
||||
this.sipWkDay = "Tue";
|
||||
break;
|
||||
case 4:
|
||||
this.sipWkDay = "Wed";
|
||||
break;
|
||||
case 5:
|
||||
this.sipWkDay = "Thu";
|
||||
break;
|
||||
case 6:
|
||||
this.sipWkDay = "Fri";
|
||||
break;
|
||||
case 7:
|
||||
this.sipWkDay = "Sat";
|
||||
break;
|
||||
default:
|
||||
InternalErrorHandler.handleException("No date map for wkday " + this.wkday);
|
||||
}
|
||||
|
||||
this.day = this.javaCal.get(Calendar.DATE);
|
||||
this.month = this.javaCal.get(Calendar.MONTH);
|
||||
switch(this.month) {
|
||||
case 0:
|
||||
this.sipMonth = "Jan";
|
||||
break;
|
||||
case 1:
|
||||
this.sipMonth = "Feb";
|
||||
break;
|
||||
case 2:
|
||||
this.sipMonth = "Mar";
|
||||
break;
|
||||
case 3:
|
||||
this.sipMonth = "Apr";
|
||||
break;
|
||||
case 4:
|
||||
this.sipMonth = "May";
|
||||
break;
|
||||
case 5:
|
||||
this.sipMonth = "Jun";
|
||||
break;
|
||||
case 6:
|
||||
this.sipMonth = "Jul";
|
||||
break;
|
||||
case 7:
|
||||
this.sipMonth = "Aug";
|
||||
break;
|
||||
case 8:
|
||||
this.sipMonth = "Sep";
|
||||
break;
|
||||
case 9:
|
||||
this.sipMonth = "Oct";
|
||||
break;
|
||||
case 10:
|
||||
this.sipMonth = "Nov";
|
||||
break;
|
||||
case 11:
|
||||
this.sipMonth = "Dec";
|
||||
break;
|
||||
default:
|
||||
InternalErrorHandler.handleException("No date map for month " + this.month);
|
||||
}
|
||||
|
||||
this.year = this.javaCal.get(Calendar.YEAR);
|
||||
this.hour = this.javaCal.get(Calendar.HOUR_OF_DAY);
|
||||
this.minute = this.javaCal.get(Calendar.MINUTE);
|
||||
this.second = this.javaCal.get(Calendar.SECOND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder encode(StringBuilder var1) {
|
||||
String var2;
|
||||
if (this.month < 9) {
|
||||
var2 = "0" + (this.month + 1);
|
||||
} else {
|
||||
var2 = "" + (this.month + 1);
|
||||
}
|
||||
|
||||
String var3;
|
||||
if (this.day < 10) {
|
||||
var3 = "0" + this.day;
|
||||
} else {
|
||||
var3 = "" + this.day;
|
||||
}
|
||||
|
||||
String var4;
|
||||
if (this.hour < 10) {
|
||||
var4 = "0" + this.hour;
|
||||
} else {
|
||||
var4 = "" + this.hour;
|
||||
}
|
||||
|
||||
String var5;
|
||||
if (this.minute < 10) {
|
||||
var5 = "0" + this.minute;
|
||||
} else {
|
||||
var5 = "" + this.minute;
|
||||
}
|
||||
|
||||
String var6;
|
||||
if (this.second < 10) {
|
||||
var6 = "0" + this.second;
|
||||
} else {
|
||||
var6 = "" + this.second;
|
||||
}
|
||||
|
||||
int var8 = this.javaCal.get(Calendar.MILLISECOND);
|
||||
String var7;
|
||||
if (var8 < 10) {
|
||||
var7 = "00" + var8;
|
||||
} else if (var8 < 100) {
|
||||
var7 = "0" + var8;
|
||||
} else {
|
||||
var7 = "" + var8;
|
||||
}
|
||||
|
||||
return var1.append(this.year).append("-").append(var2).append("-").append(var3).append("T").append(var4).append(":").append(var5).append(":").append(var6).append(".").append(var7);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SipDeviceSummary {
|
||||
public SipDeviceSummary(SipDevice device) {
|
||||
this.manufacturer = device.getManufacturer();
|
||||
this.firmware = device.getFirmware();
|
||||
this.transport = device.getTransport();
|
||||
this.streammode = device.getStreammode();
|
||||
this.port = device.getPort();
|
||||
this.hostaddress = device.getHostaddress();
|
||||
}
|
||||
public SipDeviceSummary() {
|
||||
|
||||
}
|
||||
private String manufacturer;
|
||||
private String firmware;
|
||||
private String transport;
|
||||
private String streammode;
|
||||
private Integer port;
|
||||
private String hostaddress;
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Stream {
|
||||
private String app;
|
||||
private String deviceID;
|
||||
private String channelId;
|
||||
private String ssrc;
|
||||
private String streamId;
|
||||
private String ip;
|
||||
private String playurl;
|
||||
private String mediaServerId;
|
||||
private JSONArray tracks;
|
||||
private String startTime;
|
||||
private String endTime;
|
||||
private boolean pause;
|
||||
|
||||
private String flv;
|
||||
private String https_flv;
|
||||
private String ws_flv;
|
||||
private String wss_flv;
|
||||
private String fmp4;
|
||||
private String https_fmp4;
|
||||
private String ws_fmp4;
|
||||
private String wss_fmp4;
|
||||
private String hls;
|
||||
private String https_hls;
|
||||
private String ws_hls;
|
||||
private String wss_hls;
|
||||
private String rtmp;
|
||||
private String rtsp;
|
||||
private String rtc;
|
||||
|
||||
public Stream(String deviceSipId, String channelId, String streamId, String ssrc) {
|
||||
this.deviceID = deviceSipId;
|
||||
this.channelId = channelId;
|
||||
this.streamId = streamId;
|
||||
this.ssrc = ssrc;
|
||||
}
|
||||
public Stream() {}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class StreamURL {
|
||||
private String protocol;
|
||||
private String host;
|
||||
private int port = -1;
|
||||
private String file;
|
||||
private String url;
|
||||
|
||||
public StreamURL() {
|
||||
}
|
||||
|
||||
public StreamURL(String protocol, String host, int port, String file) {
|
||||
this.protocol = protocol;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (protocol != null && host != null && port != -1 ) {
|
||||
return String.format("%s://%s:%s/%s", protocol, host, port, file);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import com.fastbee.sip.enums.SessionType;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class VideoSessionInfo {
|
||||
//流基本信息
|
||||
private String mediaServerId;
|
||||
private String deviceId;
|
||||
private String channelId;
|
||||
private String stream;
|
||||
private String ssrc;
|
||||
private int port;
|
||||
private String streamMode;
|
||||
private SessionType type;
|
||||
//流状态
|
||||
private boolean pushing;
|
||||
private boolean recording;
|
||||
private int onPlaytime;
|
||||
private int player;
|
||||
private boolean videoRecord;
|
||||
private boolean enable_fmp4;
|
||||
private boolean enable_hls;
|
||||
private boolean enable_rtmp;
|
||||
private boolean enable_rtsp;
|
||||
|
||||
//录像信息
|
||||
String startTime;
|
||||
String endTime;
|
||||
int downloadSpeed;
|
||||
}
|
@ -0,0 +1,206 @@
|
||||
package com.fastbee.sip.model;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ZlmMediaServer {
|
||||
@JSONField(name = "api.apiDebug")
|
||||
private String apiDebug;
|
||||
|
||||
@JSONField(name = "api.secret")
|
||||
private String apiSecret;
|
||||
|
||||
@JSONField(name = "ffmpeg.bin")
|
||||
private String ffmpegBin;
|
||||
|
||||
@JSONField(name = "ffmpeg.cmd")
|
||||
private String ffmpegCmd;
|
||||
|
||||
@JSONField(name = "ffmpeg.log")
|
||||
private String ffmpegLog;
|
||||
|
||||
@JSONField(name = "general.mediaServerId")
|
||||
private String mediaServerId;
|
||||
|
||||
@JSONField(name = "general.enableVhost")
|
||||
private String generalEnableVhost;
|
||||
|
||||
@JSONField(name = "general.flowThreshold")
|
||||
private String generalFlowThreshold;
|
||||
|
||||
@JSONField(name = "general.maxStreamWaitMS")
|
||||
private String generalMaxStreamWaitMS;
|
||||
|
||||
@JSONField(name = "general.streamNoneReaderDelayMS")
|
||||
private String generalStreamNoneReaderDelayMS;
|
||||
|
||||
private String localIP;
|
||||
|
||||
private String wanIp;
|
||||
|
||||
@JSONField(name = "hls.fileBufSize")
|
||||
private String hlsFileBufSize;
|
||||
|
||||
@JSONField(name = "hls.filePath")
|
||||
private String hlsFilePath;
|
||||
|
||||
@JSONField(name = "hls.segDur")
|
||||
private String hlsSegDur;
|
||||
|
||||
@JSONField(name = "hls.segNum")
|
||||
private String hlsSegNum;
|
||||
|
||||
@JSONField(name = "hook.access_file_except_hls")
|
||||
private String hookAccessFileExceptHLS;
|
||||
|
||||
@JSONField(name = "hook.admin_params")
|
||||
private String hookAdminParams;
|
||||
|
||||
@JSONField(name = "hook.enable")
|
||||
private String hookEnable;
|
||||
|
||||
@JSONField(name = "hook.on_flow_report")
|
||||
private String hookOnFlowReport;
|
||||
|
||||
@JSONField(name = "hook.on_http_access")
|
||||
private String hookOnHttpAccess;
|
||||
|
||||
@JSONField(name = "hook.on_play")
|
||||
private String hookOnPlay;
|
||||
|
||||
@JSONField(name = "hook.on_publish")
|
||||
private String hookOnPublish;
|
||||
|
||||
@JSONField(name = "hook.on_record_mp4")
|
||||
private String hookOnRecordMp4;
|
||||
|
||||
@JSONField(name = "hook.on_rtsp_auth")
|
||||
private String hookOnRtspAuth;
|
||||
|
||||
@JSONField(name = "hook.on_rtsp_realm")
|
||||
private String hookOnRtspRealm;
|
||||
|
||||
@JSONField(name = "hook.on_shell_login")
|
||||
private String hookOnShellLogin;
|
||||
|
||||
@JSONField(name = "hook.on_stream_changed")
|
||||
private String hookOnStreamChanged;
|
||||
|
||||
@JSONField(name = "hook.on_stream_none_reader")
|
||||
private String hookOnStreamNoneReader;
|
||||
|
||||
@JSONField(name = "hook.on_stream_not_found")
|
||||
private String hookOnStreamNotFound;
|
||||
|
||||
@JSONField(name = "hook.timeoutSec")
|
||||
private String hookTimeoutSec;
|
||||
|
||||
@JSONField(name = "http.charSet")
|
||||
private String httpCharSet;
|
||||
|
||||
@JSONField(name = "http.keepAliveSecond")
|
||||
private String httpKeepAliveSecond;
|
||||
|
||||
@JSONField(name = "http.maxReqCount")
|
||||
private String httpMaxReqCount;
|
||||
|
||||
@JSONField(name = "http.maxReqSize")
|
||||
private String httpMaxReqSize;
|
||||
|
||||
@JSONField(name = "http.notFound")
|
||||
private String httpNotFound;
|
||||
|
||||
@JSONField(name = "http.port")
|
||||
private String httpPort;
|
||||
|
||||
@JSONField(name = "http.rootPath")
|
||||
private String httpRootPath;
|
||||
|
||||
@JSONField(name = "http.sendBufSize")
|
||||
private String httpSendBufSize;
|
||||
|
||||
@JSONField(name = "http.sslport")
|
||||
private String httpSSLport;
|
||||
|
||||
@JSONField(name = "multicast.addrMax")
|
||||
private String multicastAddrMax;
|
||||
|
||||
@JSONField(name = "multicast.addrMin")
|
||||
private String multicastAddrMin;
|
||||
|
||||
@JSONField(name = "multicast.udpTTL")
|
||||
private String multicastUdpTTL;
|
||||
|
||||
@JSONField(name = "record.appName")
|
||||
private String recordAppName;
|
||||
|
||||
@JSONField(name = "record.filePath")
|
||||
private String recordFilePath;
|
||||
|
||||
@JSONField(name = "record.fileSecond")
|
||||
private String recordFileSecond;
|
||||
|
||||
@JSONField(name = "record.sampleMS")
|
||||
private String recordFileSampleMS;
|
||||
|
||||
@JSONField(name = "rtmp.handshakeSecond")
|
||||
private String rtmpHandshakeSecond;
|
||||
|
||||
@JSONField(name = "rtmp.keepAliveSecond")
|
||||
private String rtmpKeepAliveSecond;
|
||||
|
||||
@JSONField(name = "rtmp.modifyStamp")
|
||||
private String rtmpModifyStamp;
|
||||
|
||||
@JSONField(name = "rtmp.port")
|
||||
private String rtmpPort;
|
||||
|
||||
@JSONField(name = "rtp.audioMtuSize")
|
||||
private String rtpAudioMtuSize;
|
||||
|
||||
@JSONField(name = "rtp.clearCount")
|
||||
private String rtpClearCount;
|
||||
|
||||
@JSONField(name = "rtp.cycleMS")
|
||||
private String rtpCycleMS;
|
||||
|
||||
@JSONField(name = "rtp.maxRtpCount")
|
||||
private String rtpMaxRtpCount;
|
||||
|
||||
@JSONField(name = "rtp.videoMtuSize")
|
||||
private String rtpVideoMtuSize;
|
||||
|
||||
@JSONField(name = "rtp_proxy.checkSource")
|
||||
private String rtpProxyCheckSource;
|
||||
|
||||
@JSONField(name = "rtp_proxy.dumpDir")
|
||||
private String rtpProxyDumpDir;
|
||||
|
||||
@JSONField(name = "rtp_proxy.port")
|
||||
private String rtpProxyPort;
|
||||
|
||||
@JSONField(name = "rtp_proxy.timeoutSec")
|
||||
private String rtpProxyTimeoutSec;
|
||||
|
||||
@JSONField(name = "rtsp.authBasic")
|
||||
private String rtspAuthBasic;
|
||||
|
||||
@JSONField(name = "rtsp.handshakeSecond")
|
||||
private String rtspHandshakeSecond;
|
||||
|
||||
@JSONField(name = "rtsp.keepAliveSecond")
|
||||
private String rtspKeepAliveSecond;
|
||||
|
||||
@JSONField(name = "rtsp.port")
|
||||
private String rtspPort;
|
||||
|
||||
@JSONField(name = "rtsp.sslport")
|
||||
private String rtspSSlport;
|
||||
|
||||
@JSONField(name = "shell.maxReqSize")
|
||||
private String shellMaxReqSize;
|
||||
|
||||
@JSONField(name = "shell.shell")
|
||||
private String shellPhell;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.fastbee.sip.server;
|
||||
|
||||
import com.fastbee.sip.handler.IReqHandler;
|
||||
import com.fastbee.sip.handler.IResHandler;
|
||||
|
||||
import javax.sip.SipListener;
|
||||
|
||||
public interface IGBListener extends SipListener {
|
||||
public void addRequestProcessor(String method, IReqHandler processor);
|
||||
public void addResponseProcessor(String method, IResHandler processor);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.fastbee.sip.server;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
|
||||
public interface IRtspCmd {
|
||||
void playPause(SipDevice device, String channelId, String streamId);
|
||||
void playReplay(SipDevice device, String channelId, String streamId);
|
||||
void playBackSeek(SipDevice device, String channelId, String streamId, long seektime);
|
||||
void playBackSpeed(SipDevice device, String channelId, String streamId, Integer speed);
|
||||
void setCseq(String streamId);
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.fastbee.sip.server;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.model.VideoSessionInfo;
|
||||
|
||||
public interface ISipCmd {
|
||||
VideoSessionInfo playStreamCmd(SipDevice device, String channelId, boolean record);
|
||||
VideoSessionInfo playbackStreamCmd(SipDevice device, String channelId, String startTime, String endTime);
|
||||
VideoSessionInfo downloadStreamCmd(SipDevice device, String channelId, String startTime, String endTime, int downloadSpeed);
|
||||
void streamByeCmd(SipDevice device, String channelId, String stream, String ssrc);
|
||||
void streamByeCmd(String deviceId, String channelId, String stream, String ssrc);
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.fastbee.sip.server;
|
||||
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.server.msg.DeviceControl;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.sip.RequestEvent;
|
||||
import java.util.Date;
|
||||
|
||||
public interface MessageInvoker {
|
||||
|
||||
/**
|
||||
* 发送订阅报警指令
|
||||
*
|
||||
* @param device 设备信息
|
||||
* @param startAlarmPriority 开始报警级别
|
||||
* @param endAlarmPriority 结束报警级别
|
||||
* @param expires 过期时间
|
||||
* @param alarmMethod 报警方式
|
||||
* @param startAlarmTime 开始报警时间
|
||||
* @param endAlarmTime 结束报警时间
|
||||
* @return void
|
||||
*/
|
||||
void subscribe(@Nonnull SipDevice device,
|
||||
int startAlarmPriority,
|
||||
int endAlarmPriority,
|
||||
int expires,
|
||||
@Nonnull String alarmMethod,
|
||||
@Nullable Date startAlarmTime,
|
||||
@Nullable Date endAlarmTime);
|
||||
|
||||
/**
|
||||
* 发送设备控制指令,{@link DeviceControl#getDeviceId()}为通道ID
|
||||
*
|
||||
* @param device 设备信息
|
||||
* @param command 控制指令
|
||||
* @return void
|
||||
*/
|
||||
void deviceControl(SipDevice device, DeviceControl command);
|
||||
|
||||
/**
|
||||
* 获取设备详细信息
|
||||
*
|
||||
* @param device 设备信息
|
||||
* @return 详细信息
|
||||
*/
|
||||
boolean deviceInfoQuery(SipDevice device);
|
||||
|
||||
/**
|
||||
* 获取通道列表
|
||||
*
|
||||
* @param device 设备信息
|
||||
* @return 通道列表
|
||||
*/
|
||||
boolean catalogQuery(SipDevice device);
|
||||
|
||||
boolean recordInfoQuery(SipDevice device, String sn, String channelId, Date start, Date end);
|
||||
|
||||
|
||||
SipMessage messageToObj(RequestEvent event);
|
||||
|
||||
<T> T getExecResult(String key, long timeout);
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package com.fastbee.sip.server;
|
||||
|
||||
import javax.sip.*;
|
||||
import javax.sip.header.CallIdHeader;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
import java.util.TooManyListenersException;
|
||||
|
||||
public class NullSipProvider implements SipProvider {
|
||||
@Override
|
||||
public void addSipListener(SipListener sipListener) throws TooManyListenersException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSipListener(SipListener sipListener) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SipStack getSipStack() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListeningPoint getListeningPoint() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListeningPoint[] getListeningPoints() {
|
||||
return new ListeningPoint[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListeningPoint(ListeningPoint listeningPoint) throws ObjectInUseException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListeningPoint(ListeningPoint listeningPoint) throws ObjectInUseException, TransportAlreadySupportedException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListeningPoint getListeningPoint(String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListeningPoint(ListeningPoint listeningPoint) throws ObjectInUseException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallIdHeader getNewCallId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTransaction getNewClientTransaction(Request request) throws TransactionUnavailableException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerTransaction getNewServerTransaction(Request request) throws TransactionAlreadyExistsException, TransactionUnavailableException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRequest(Request request) throws SipException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendResponse(Response response) throws SipException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog getNewDialog(Transaction transaction) throws SipException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutomaticDialogSupportEnabled(boolean b) {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.fastbee.sip.server;
|
||||
|
||||
import com.fastbee.sip.model.RecordList;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@Component
|
||||
public class RecordCacheManager {
|
||||
private final ConcurrentHashMap<String, RecordList> recordMap = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();
|
||||
|
||||
public void put(String key,RecordList list){
|
||||
recordMap.putIfAbsent(key, list);
|
||||
}
|
||||
|
||||
public RecordList get(String key){
|
||||
RecordList ret = recordMap.get(key);
|
||||
if (ret == null) {
|
||||
ret = new RecordList();
|
||||
recordMap.putIfAbsent(key, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void remove(String key) {
|
||||
recordMap.remove(key);
|
||||
lockMap.remove(key);
|
||||
}
|
||||
|
||||
public void addlock(String key){
|
||||
lockMap.put(key,new ReentrantLock());
|
||||
}
|
||||
|
||||
public ReentrantLock getlock(String key){
|
||||
return lockMap.get(key);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,267 @@
|
||||
package com.fastbee.sip.server;
|
||||
|
||||
import com.fastbee.sip.domain.SipConfig;
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.model.InviteInfo;
|
||||
import com.fastbee.sip.model.VideoSessionInfo;
|
||||
import com.fastbee.sip.service.IInviteService;
|
||||
import com.fastbee.sip.service.ISipCacheService;
|
||||
import com.fastbee.sip.util.SipUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.sip.*;
|
||||
import javax.sip.address.Address;
|
||||
import javax.sip.address.SipURI;
|
||||
import javax.sip.header.*;
|
||||
import javax.sip.message.Request;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Component
|
||||
public class ReqMsgHeaderBuilder {
|
||||
@Autowired
|
||||
private SipFactory sipFactory;
|
||||
|
||||
@Autowired
|
||||
@Qualifier(value = "udpSipServer")
|
||||
private SipProvider sipserver;
|
||||
|
||||
@Autowired
|
||||
private VideoSessionManager streamSession;
|
||||
|
||||
@Autowired
|
||||
private ISipCacheService sipCacheService;
|
||||
|
||||
@Autowired
|
||||
private IInviteService inviteService;
|
||||
|
||||
/**
|
||||
* 创建请求消息
|
||||
*
|
||||
* @param device
|
||||
* @param content
|
||||
* @param fromTag
|
||||
* @return
|
||||
* @throws ParseException
|
||||
* @throws InvalidArgumentException
|
||||
* @throws PeerUnavailableException
|
||||
*/
|
||||
public Request createMessageRequest(SipDevice device, SipConfig sipConfig, String content, String fromTag)
|
||||
throws ParseException, InvalidArgumentException, PeerUnavailableException {
|
||||
Request request = null;
|
||||
// sipuri
|
||||
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceSipId(),
|
||||
device.getHostaddress());
|
||||
// via
|
||||
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
|
||||
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(),
|
||||
sipConfig.getPort(), device.getTransport(), SipUtil.getNewViaTag());
|
||||
viaHeader.setRPort();
|
||||
viaHeaders.add(viaHeader);
|
||||
// from
|
||||
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getServerSipid(),
|
||||
sipConfig.getIp() + ":" + sipConfig.getPort());
|
||||
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
|
||||
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
|
||||
// to
|
||||
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceSipId(),
|
||||
sipConfig.getDomain());
|
||||
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
|
||||
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, SipUtil.getNewTag());
|
||||
// callid
|
||||
CallIdHeader callIdHeader = sipserver.getNewCallId();
|
||||
// Forwards
|
||||
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
|
||||
// ceq
|
||||
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(sipCacheService.getCSEQ(sipConfig.getServerSipid()), Request.MESSAGE);
|
||||
|
||||
request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader,
|
||||
fromHeader, toHeader, viaHeaders, maxForwards);
|
||||
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION",
|
||||
"MANSCDP+xml");
|
||||
request.setContent(content, contentTypeHeader);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
public Request createInviteRequest(SipDevice device, SipConfig sipConfig, String channelId, String content, String ssrc, String fromTag) throws ParseException, InvalidArgumentException, PeerUnavailableException {
|
||||
Request request = null;
|
||||
// 请求行
|
||||
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostaddress());
|
||||
// via
|
||||
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
|
||||
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(),
|
||||
device.getTransport(), SipUtil.getNewViaTag());
|
||||
viaHeader.setRPort();
|
||||
viaHeaders.add(viaHeader);
|
||||
// from
|
||||
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getServerSipid(),
|
||||
sipConfig.getDomain());
|
||||
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
|
||||
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); // 必须要有标记,否则无法创建会话,无法回应ack
|
||||
// to
|
||||
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, sipConfig.getDomain());
|
||||
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
|
||||
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, null);
|
||||
|
||||
// callid
|
||||
CallIdHeader callIdHeader = sipserver.getNewCallId();
|
||||
|
||||
// Forwards
|
||||
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
|
||||
|
||||
// ceq
|
||||
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(sipCacheService.getCSEQ(sipConfig.getServerSipid()), Request.INVITE);
|
||||
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,
|
||||
fromHeader, toHeader, viaHeaders, maxForwards);
|
||||
|
||||
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
|
||||
.createSipURI(sipConfig.getServerSipid(), sipConfig.getIp() + ":" + sipConfig.getPort()));
|
||||
|
||||
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
|
||||
// Subject
|
||||
SubjectHeader subjectHeader = sipFactory.createHeaderFactory()
|
||||
.createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getIp(), 0));
|
||||
request.addHeader(subjectHeader);
|
||||
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION",
|
||||
"SDP");
|
||||
request.setContent(content, contentTypeHeader);
|
||||
return request;
|
||||
}
|
||||
|
||||
public Request createPlaybackInviteRequest(SipDevice device, SipConfig sipConfig, String channelId, String content, String viaTag, String fromTag) throws ParseException, InvalidArgumentException, PeerUnavailableException {
|
||||
Request request = null;
|
||||
// 请求行
|
||||
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId,
|
||||
device.getHostaddress());
|
||||
// via
|
||||
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
|
||||
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(),
|
||||
device.getTransport(), viaTag);
|
||||
viaHeader.setRPort();
|
||||
viaHeaders.add(viaHeader);
|
||||
// from
|
||||
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getServerSipid(),
|
||||
sipConfig.getDomain());
|
||||
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
|
||||
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); // 必须要有标记,否则无法创建会话,无法回应ack
|
||||
// to
|
||||
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostaddress());
|
||||
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
|
||||
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, null);
|
||||
|
||||
// callid
|
||||
CallIdHeader callIdHeader = sipserver.getNewCallId();
|
||||
|
||||
// Forwards
|
||||
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
|
||||
|
||||
// ceq
|
||||
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(sipCacheService.getCSEQ(sipConfig.getServerSipid()), Request.INVITE);
|
||||
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,
|
||||
fromHeader, toHeader, viaHeaders, maxForwards);
|
||||
|
||||
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
|
||||
.createSipURI(sipConfig.getServerSipid(), sipConfig.getIp() + ":" + sipConfig.getPort()));
|
||||
|
||||
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
|
||||
|
||||
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION",
|
||||
"SDP");
|
||||
request.setContent(content, contentTypeHeader);
|
||||
return request;
|
||||
}
|
||||
|
||||
public Request createByeRequest(SipDevice device, SipConfig sipConfig, String channelId, InviteInfo invite) throws ParseException, InvalidArgumentException, PeerUnavailableException {
|
||||
Request request = null;
|
||||
//请求行
|
||||
SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostaddress());
|
||||
// via
|
||||
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
|
||||
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(),
|
||||
device.getTransport(), SipUtil.getNewViaTag());
|
||||
viaHeader.setRPort();
|
||||
viaHeaders.add(viaHeader);
|
||||
//from
|
||||
SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getServerSipid(), sipConfig.getDomain());
|
||||
Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
|
||||
FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, invite.getFromTag());
|
||||
//to
|
||||
SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostaddress());
|
||||
Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
|
||||
ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, SipUtil.getNewTag());
|
||||
//Forwards
|
||||
MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
|
||||
//ceq
|
||||
CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(sipCacheService.getCSEQ(sipConfig.getServerSipid()), Request.BYE);
|
||||
CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(invite.getCallId());
|
||||
request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader, fromHeader, toHeader, viaHeaders, maxForwards);
|
||||
|
||||
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
|
||||
.createSipURI(sipConfig.getServerSipid(), sipConfig.getIp() + ":" + sipConfig.getPort()));
|
||||
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
|
||||
return request;
|
||||
}
|
||||
|
||||
public Request createRtspRequest(SipDevice device, SipConfig sipConfig, String channelId, String streamId, String content)
|
||||
throws PeerUnavailableException, ParseException, InvalidArgumentException {
|
||||
Request request = null;
|
||||
VideoSessionInfo info = streamSession.getSessionInfo(device.getDeviceSipId(), channelId, streamId, null);
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
Dialog dialog = streamSession.getclientTransaction(info).getDialog();
|
||||
if (dialog == null) {
|
||||
return null;
|
||||
}
|
||||
InviteInfo invite = inviteService.getInviteInfoBySSRC(info.getSsrc());
|
||||
if (invite == null) {
|
||||
return null;
|
||||
}
|
||||
// 请求行
|
||||
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostaddress());
|
||||
// via
|
||||
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
|
||||
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(getLocalIp(sipConfig.getIp()), sipConfig.getPort(),
|
||||
device.getTransport(), invite.getViaTag());
|
||||
viaHeader.setRPort();
|
||||
viaHeaders.add(viaHeader);
|
||||
// from
|
||||
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getServerSipid(),
|
||||
sipConfig.getDomain());
|
||||
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
|
||||
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, invite.getFromTag());
|
||||
// to
|
||||
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostaddress());
|
||||
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
|
||||
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, dialog.getRemoteTag());
|
||||
// callid
|
||||
CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(invite.getCallId());;
|
||||
// Forwards
|
||||
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
|
||||
// ceq
|
||||
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(sipCacheService.getCSEQ(sipConfig.getServerSipid()), Request.INFO);
|
||||
|
||||
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,
|
||||
fromHeader, toHeader, viaHeaders, maxForwards);
|
||||
|
||||
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
|
||||
.createSipURI(sipConfig.getServerSipid(), sipConfig.getIp() + ":" + sipConfig.getPort()));
|
||||
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
|
||||
|
||||
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application",
|
||||
"MANSRTSP");
|
||||
request.setContent(content, contentTypeHeader);
|
||||
return request;
|
||||
}
|
||||
|
||||
public String getLocalIp(String deviceLocalIp) {
|
||||
if (!ObjectUtils.isEmpty(deviceLocalIp)) {
|
||||
return deviceLocalIp;
|
||||
}
|
||||
return sipserver.getListeningPoint().getIPAddress();
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.fastbee.sip.server;
|
||||
|
||||
import javax.sip.header.AuthorizationHeader;
|
||||
import javax.sip.header.CallIdHeader;
|
||||
import javax.sip.message.Request;
|
||||
|
||||
public interface RequestBuilder {
|
||||
|
||||
RequestBuilder requestLine(String sipId, String host, int port);
|
||||
|
||||
RequestBuilder user(String user);
|
||||
|
||||
RequestBuilder via(String host, int port, String transport, String viaTag);
|
||||
|
||||
RequestBuilder from(String sipId, String domain, String fromTag);
|
||||
|
||||
RequestBuilder to(String user, String domain, String toTag);
|
||||
|
||||
RequestBuilder contact(String user, int port);
|
||||
|
||||
RequestBuilder subject(String subject);
|
||||
|
||||
RequestBuilder cSeq(int cSeq);
|
||||
|
||||
RequestBuilder method(String method);
|
||||
|
||||
RequestBuilder contentxml(byte[] content);
|
||||
|
||||
RequestBuilder contentsdp(byte[] content);
|
||||
|
||||
RequestBuilder authorization(AuthorizationHeader header);
|
||||
|
||||
Request build(CallIdHeader callId);
|
||||
|
||||
default RequestBuilder invite() {
|
||||
return method(Request.INVITE);
|
||||
}
|
||||
|
||||
default RequestBuilder message() {
|
||||
return method(Request.MESSAGE);
|
||||
}
|
||||
|
||||
default RequestBuilder subscribe() {
|
||||
return method(Request.SUBSCRIBE);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,97 @@
|
||||
package com.fastbee.sip.server;
|
||||
|
||||
import com.fastbee.sip.conf.SysSipConfig;
|
||||
import com.fastbee.sip.domain.MediaServer;
|
||||
import com.fastbee.sip.model.ZlmMediaServer;
|
||||
import com.fastbee.sip.service.IMediaServerService;
|
||||
import com.fastbee.sip.service.ISipCacheService;
|
||||
import com.fastbee.sip.service.ISipConfigService;
|
||||
import com.fastbee.sip.util.ZlmApiUtils;
|
||||
import gov.nist.javax.sip.SipStackImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import javax.sip.*;
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@Order(13)
|
||||
public class SipLayer {
|
||||
@Autowired
|
||||
private SysSipConfig sipConfig;
|
||||
|
||||
@Autowired
|
||||
private IGBListener gbSIPListener;
|
||||
|
||||
@Autowired
|
||||
private ZlmApiUtils zlmApiUtils;
|
||||
|
||||
@Autowired
|
||||
private ISipCacheService sipCacheService;
|
||||
|
||||
@Autowired
|
||||
private ISipConfigService sipConfigService;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
private SipStack sipStack;
|
||||
private SipFactory sipFactory;
|
||||
|
||||
|
||||
@Bean("sipFactory")
|
||||
SipFactory createSipFactory() {
|
||||
sipFactory = SipFactory.getInstance();
|
||||
sipFactory.setPathName("gov.nist");
|
||||
if (sipConfig.isEnabled()) {
|
||||
//缓存zlm服务器配置
|
||||
MediaServer media = mediaServerService.selectMediaServerBytenantId(1L);
|
||||
if (media != null) {
|
||||
ZlmMediaServer mediaServer = zlmApiUtils.getMediaServerConfig(media);
|
||||
if (mediaServer != null) {
|
||||
log.info("zlm配置获取成功成功...");
|
||||
sipCacheService.updateMediaInfo(mediaServer);
|
||||
mediaServerService.syncMediaServer(media, media.getSecret());
|
||||
}
|
||||
}
|
||||
}
|
||||
return sipFactory;
|
||||
}
|
||||
|
||||
@Bean("sipStack")
|
||||
@DependsOn("sipFactory")
|
||||
SipStack createSipStack() throws PeerUnavailableException {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP");
|
||||
properties.setProperty("javax.sip.IP_ADDRESS", sipConfig.getIp());
|
||||
properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "false");
|
||||
properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "0");
|
||||
properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "sip_server_log");
|
||||
properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "sip_debug_log");
|
||||
sipStack = (SipStackImpl) sipFactory.createSipStack(properties);
|
||||
return sipStack;
|
||||
}
|
||||
|
||||
@Bean("udpSipServer")
|
||||
@DependsOn("sipStack")
|
||||
SipProvider startUdpListener() throws Exception {
|
||||
if (sipConfig.isEnabled()) {
|
||||
log.info("startUdpListener");
|
||||
ListeningPoint udpListeningPoint = sipStack.createListeningPoint(sipConfig.getIp(), sipConfig.getPort(), "UDP");
|
||||
SipProvider udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
|
||||
udpSipProvider.addSipListener(gbSIPListener);
|
||||
log.info("Sip Server UDP 启动成功 port {}", sipConfig.getPort());
|
||||
sipConfigService.syncSipConfig(sipConfig);
|
||||
return udpSipProvider;
|
||||
} else {
|
||||
return new NullSipProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.fastbee.sip.server;
|
||||
|
||||
public interface SipMessage {
|
||||
String getDeviceId();
|
||||
|
||||
String getSn();
|
||||
|
||||
default int totalPart() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
default int numberOfPart() {
|
||||
return 1;
|
||||
}
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
package com.fastbee.sip.server;
|
||||
|
||||
import com.fastbee.common.core.redis.RedisCache;
|
||||
import com.fastbee.common.core.redis.RedisKeyBuilder;
|
||||
import com.fastbee.sip.enums.SessionType;
|
||||
import com.fastbee.sip.model.InviteInfo;
|
||||
import com.fastbee.sip.model.VideoSessionInfo;
|
||||
import com.fastbee.sip.util.SipUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.sip.ClientTransaction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
@Component
|
||||
public class VideoSessionManager {
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
private final ConcurrentHashMap<String, ClientTransaction> sessionMap = new ConcurrentHashMap<>();
|
||||
|
||||
public String createPlaySsrc(String domain) {
|
||||
return SipUtil.getPlaySsrc(domain);
|
||||
}
|
||||
|
||||
public String createPlayBackSsrc(String domain) {
|
||||
return SipUtil.getPlayBackSsrc(domain);
|
||||
}
|
||||
|
||||
public void put(VideoSessionInfo info, ClientTransaction client) {
|
||||
String ssrc = info.getSsrc();
|
||||
if (info.getType() == SessionType.play || info.getType() == SessionType.playrecord) {
|
||||
ssrc = info.getType().name();
|
||||
}
|
||||
String key = RedisKeyBuilder.buildStreamCacheKey(info.getDeviceId(), info.getChannelId(), info.getStream(), ssrc);
|
||||
redisCache.setCacheObject(key, info);
|
||||
if (!ObjectUtils.isEmpty(client)) {
|
||||
key = RedisKeyBuilder.buildStreamCacheKey(info.getDeviceId(), info.getChannelId(), info.getStream(), info.getSsrc());
|
||||
sessionMap.put(key, client);
|
||||
}
|
||||
}
|
||||
|
||||
public ClientTransaction getclientTransaction(VideoSessionInfo info) {
|
||||
String key = RedisKeyBuilder.buildStreamCacheKey(info.getDeviceId(), info.getChannelId(), info.getStream(), info.getSsrc());
|
||||
return sessionMap.get(key);
|
||||
}
|
||||
|
||||
public ClientTransaction getclientTransaction(VideoSessionInfo info, InviteInfo invite) {
|
||||
String key = RedisKeyBuilder.buildStreamCacheKey(info.getDeviceId(), info.getChannelId(), info.getStream(), invite.getSsrc());
|
||||
return sessionMap.get(key);
|
||||
}
|
||||
|
||||
public VideoSessionInfo getSessionInfo(String deviceId, String channelId, String stream, String callId) {
|
||||
if (ObjectUtils.isEmpty(deviceId)) {
|
||||
deviceId = "*";
|
||||
}
|
||||
if (ObjectUtils.isEmpty(channelId)) {
|
||||
channelId = "*";
|
||||
}
|
||||
if (ObjectUtils.isEmpty(stream)) {
|
||||
stream = "*";
|
||||
}
|
||||
if (ObjectUtils.isEmpty(callId)) {
|
||||
callId = "*";
|
||||
}
|
||||
String key = RedisKeyBuilder.buildStreamCacheKey(deviceId, channelId, stream, callId);
|
||||
List<Object> scanResult = redisCache.scan(key);
|
||||
if (scanResult.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
return (VideoSessionInfo) redisCache.getCacheObject((String) scanResult.get(0));
|
||||
}
|
||||
|
||||
public VideoSessionInfo getSessionInfoByCallId(String callId) {
|
||||
if (ObjectUtils.isEmpty(callId)) {
|
||||
return null;
|
||||
}
|
||||
String key = RedisKeyBuilder.buildStreamCacheKey("*", "*", "*", callId);
|
||||
List<Object> scanResult = redisCache.scan(key);
|
||||
if (!scanResult.isEmpty()) {
|
||||
return (VideoSessionInfo) redisCache.getCacheObject((String) scanResult.get(0));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public VideoSessionInfo getSessionInfoBySSRC(String SSRC) {
|
||||
if (ObjectUtils.isEmpty(SSRC)) {
|
||||
return null;
|
||||
}
|
||||
String key = RedisKeyBuilder.buildStreamCacheKey("*", "*", SSRC, "*");
|
||||
List<Object> scanResult = redisCache.scan(key);
|
||||
if (!scanResult.isEmpty()) {
|
||||
return (VideoSessionInfo) redisCache.getCacheObject((String) scanResult.get(0));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<VideoSessionInfo> getSessionInfoForAll(String deviceId, String channelId, String stream, String callId) {
|
||||
if (ObjectUtils.isEmpty(deviceId)) {
|
||||
deviceId = "*";
|
||||
}
|
||||
if (ObjectUtils.isEmpty(channelId)) {
|
||||
channelId = "*";
|
||||
}
|
||||
if (ObjectUtils.isEmpty(stream)) {
|
||||
stream = "*";
|
||||
}
|
||||
if (ObjectUtils.isEmpty(callId)) {
|
||||
callId = "*";
|
||||
}
|
||||
String key = RedisKeyBuilder.buildStreamCacheKey(deviceId, channelId, stream, callId);
|
||||
List<Object> scanResult = redisCache.scan(key);
|
||||
if (scanResult.size() == 0) {
|
||||
return emptyList();
|
||||
}
|
||||
List<VideoSessionInfo> result = new ArrayList<>();
|
||||
for (Object keyObj : scanResult) {
|
||||
result.add((VideoSessionInfo) redisCache.getCacheObject((String) keyObj));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getMediaServerId(String deviceId, String channelId, String stream) {
|
||||
VideoSessionInfo ssrcTransaction = getSessionInfo(deviceId, channelId, null, stream);
|
||||
if (ssrcTransaction == null) {
|
||||
return null;
|
||||
}
|
||||
return ssrcTransaction.getMediaServerId();
|
||||
}
|
||||
|
||||
public String getSSRC(String deviceId, String channelId, String stream) {
|
||||
VideoSessionInfo ssrcTransaction = getSessionInfo(deviceId, channelId, null, stream);
|
||||
if (ssrcTransaction == null) {
|
||||
return null;
|
||||
}
|
||||
return ssrcTransaction.getSsrc();
|
||||
}
|
||||
|
||||
public void remove(String deviceId, String channelId, String stream, String callId) {
|
||||
String key = RedisKeyBuilder.buildStreamCacheKey(deviceId, channelId, stream, callId);
|
||||
if (!Objects.equals(callId, "play")) {
|
||||
redisCache.deleteObject(key);
|
||||
}
|
||||
sessionMap.remove(key);
|
||||
}
|
||||
|
||||
public void remove(String deviceId, String channelId, String stream) {
|
||||
List<VideoSessionInfo> sinfoList = getSessionInfoForAll(deviceId, channelId, stream, null);
|
||||
if (sinfoList == null || sinfoList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (VideoSessionInfo sinfo : sinfoList) {
|
||||
String key = RedisKeyBuilder.buildStreamCacheKey(deviceId, channelId, stream, sinfo.getSsrc());
|
||||
if (sinfo.getType() != SessionType.play) {
|
||||
redisCache.deleteObject(key);
|
||||
}
|
||||
sessionMap.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeByCallId(String deviceId, String channelId, String callId) {
|
||||
VideoSessionInfo sinfo = getSessionInfo(deviceId, channelId, null, callId);
|
||||
if (sinfo == null) {
|
||||
return;
|
||||
}
|
||||
String key = RedisKeyBuilder.buildStreamCacheKey(deviceId, channelId, sinfo.getStream(), sinfo.getSsrc());
|
||||
if (sinfo.getType() != SessionType.play) {
|
||||
redisCache.deleteObject(key);
|
||||
}
|
||||
sessionMap.remove(key);
|
||||
}
|
||||
|
||||
public List<VideoSessionInfo> getAllSsrc() {
|
||||
String allkey = RedisKeyBuilder.buildStreamCacheKey("*", "*", "*", "*");
|
||||
List<Object> scanResult = redisCache.scan(allkey);
|
||||
if (scanResult.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
List<VideoSessionInfo> result = new ArrayList<>();
|
||||
for (Object ssrcTransactionKey : scanResult) {
|
||||
String key = (String) ssrcTransactionKey;
|
||||
result.add((VideoSessionInfo) redisCache.getCacheObject((String) key));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package com.fastbee.sip.server.impl;
|
||||
|
||||
import com.fastbee.sip.handler.IReqHandler;
|
||||
import com.fastbee.sip.handler.IResHandler;
|
||||
import com.fastbee.sip.server.IGBListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.*;
|
||||
import javax.sip.header.CSeqHeader;
|
||||
import javax.sip.message.Response;
|
||||
import java.text.ParseException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class GBListenerImpl implements IGBListener {
|
||||
|
||||
private static final Map<String, IReqHandler> requestProcessorMap = new ConcurrentHashMap<>();
|
||||
private static final Map<String, IResHandler> responseProcessorMap = new ConcurrentHashMap<>();
|
||||
|
||||
public void addRequestProcessor(String method, IReqHandler processor) {
|
||||
requestProcessorMap.put(method, processor);
|
||||
}
|
||||
|
||||
public void addResponseProcessor(String method, IResHandler processor) {
|
||||
responseProcessorMap.put(method, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Async("taskExecutor")
|
||||
public void processRequest(RequestEvent evt) {
|
||||
String method = evt.getRequest().getMethod();
|
||||
IReqHandler sipRequestProcessor = requestProcessorMap.get(method);
|
||||
if (sipRequestProcessor == null) {
|
||||
log.warn("不支持方法{}的request", method);
|
||||
return;
|
||||
}
|
||||
requestProcessorMap.get(method).processMsg(evt);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Async("taskExecutor")
|
||||
public void processResponse(ResponseEvent evt) {
|
||||
//处理响应消息
|
||||
Response response = evt.getResponse();
|
||||
int status = response.getStatusCode();
|
||||
// 响应成功
|
||||
if ((status >= Response.OK) && (status < Response.MULTIPLE_CHOICES)) {
|
||||
log.info("response:{},",response.getReasonPhrase());
|
||||
CSeqHeader cseqHeader = (CSeqHeader) evt.getResponse().getHeader(CSeqHeader.NAME);
|
||||
String method = cseqHeader.getMethod();
|
||||
log.info("接收response响应!status:{},message:{},method:{}",status,response.getReasonPhrase(),method);
|
||||
IResHandler sipRequestProcessor = responseProcessorMap.get(method);
|
||||
if (sipRequestProcessor != null) {
|
||||
try {
|
||||
sipRequestProcessor.processMsg(evt);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else if ((status >= Response.TRYING) && (status < Response.OK)) {
|
||||
log.info("接收response响应!status:{},,message:{}",status,response.getReasonPhrase());
|
||||
} else {
|
||||
log.warn("接收到失败的response响应!status:{},,message:{}",status,response.getReasonPhrase());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processTimeout(TimeoutEvent timeoutEvent) {
|
||||
log.info("processTimeout:{}", timeoutEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processIOException(IOExceptionEvent ioExceptionEvent) {
|
||||
//log.debug("processIOException:{}", ioExceptionEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
|
||||
//log.debug("processTransactionTerminated:{}", transactionTerminatedEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
|
||||
//log.debug("processDialogTerminated:{}", dialogTerminatedEvent);
|
||||
}
|
||||
}
|
@ -0,0 +1,275 @@
|
||||
package com.fastbee.sip.server.impl;
|
||||
|
||||
import com.fastbee.common.core.redis.RedisCache;
|
||||
import com.fastbee.sip.domain.SipConfig;
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.server.MessageInvoker;
|
||||
import com.fastbee.sip.server.SipMessage;
|
||||
import com.fastbee.sip.server.msg.*;
|
||||
import com.fastbee.sip.service.ISipConfigService;
|
||||
import com.fastbee.sip.util.SipUtil;
|
||||
import com.fasterxml.jackson.core.json.JsonReadFeature;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.sip.*;
|
||||
import javax.sip.header.EventHeader;
|
||||
import javax.sip.header.ExpiresHeader;
|
||||
import javax.sip.header.Header;
|
||||
import javax.sip.message.Request;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MessageInvokerImpl implements MessageInvoker {
|
||||
@Autowired
|
||||
private SipFactory sipFactory;
|
||||
@Autowired
|
||||
private ISipConfigService sipConfigService;
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Autowired
|
||||
@Qualifier(value = "udpSipServer")
|
||||
private SipProvider sipserver;
|
||||
|
||||
public final static XmlMapper mapper = new XmlMapper();
|
||||
|
||||
private void sendRequest(Function<Integer, String> bodyBuilder,
|
||||
String requestMethod,
|
||||
SipDevice device,
|
||||
String viaTag,
|
||||
String fromTag,
|
||||
String toTag,
|
||||
Header... headers) {
|
||||
int id = (int) ((Math.random() * 9 + 1) * 100000);
|
||||
createTransaction(requestMethod, bodyBuilder.apply(id), device.getDeviceSipId(), device, viaTag, fromTag, toTag, headers);
|
||||
}
|
||||
|
||||
private void sendRequest(String xml,
|
||||
String requestMethod,
|
||||
SipDevice device,
|
||||
String viaTag,
|
||||
String fromTag,
|
||||
String toTag,
|
||||
Header... headers) {
|
||||
createTransaction(requestMethod, xml, device.getDeviceSipId(), device, viaTag, fromTag, toTag, headers);
|
||||
}
|
||||
@SneakyThrows
|
||||
private ClientTransaction createTransaction(String method,
|
||||
String xml,
|
||||
String deviceId,
|
||||
SipDevice device,
|
||||
String viaTag,
|
||||
String fromTag,
|
||||
String toTag,
|
||||
Header... headers) {
|
||||
SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
|
||||
Request request = new RequestBuilderImpl(sipFactory)
|
||||
.requestLine(deviceId, device.getIp(), device.getPort())
|
||||
.method(method)
|
||||
.user(device.getDeviceSipId())
|
||||
.via(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag)
|
||||
.from(sipConfig.getServerSipid(), sipConfig.getIp() + ":" + sipConfig.getPort(), fromTag)
|
||||
.to(deviceId, device.getHostAndPort(), toTag)
|
||||
.contentxml(xml.getBytes("GB2312"))
|
||||
.contact(sipConfig.getServerSipid(), sipConfig.getPort())
|
||||
.build(sipserver.getNewCallId());
|
||||
log.debug("prepare SIP request \n{}", request);
|
||||
for (Header header : headers) {
|
||||
request.addHeader(header);
|
||||
}
|
||||
return transmitRequest(request);
|
||||
}
|
||||
|
||||
static Map<String, Function<String, SipMessage>> valueConverter = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
|
||||
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);
|
||||
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
|
||||
mapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
|
||||
valueConverter.put("DeviceInfo", xml -> jsonNodeToObject(xml, GB28181Device.class));
|
||||
valueConverter.put("Keepalive", xml -> jsonNodeToObject(xml, KeepaliveMessage.class));
|
||||
valueConverter.put("Catalog", xml -> jsonNodeToObject(xml, CatalogInfo.class));
|
||||
valueConverter.put("Alarm", xml -> jsonNodeToObject(xml, Alarm.class));
|
||||
valueConverter.put("ConfigDownload", xml -> jsonNodeToObject(xml, ConfigDownload.class));
|
||||
valueConverter.put("DeviceControl", xml -> jsonNodeToObject(xml, DeviceControl.class));
|
||||
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static <T> T jsonNodeToObject(String xml, Class<T> tClass) {
|
||||
return mapper.readValue(xml.replace("\r\n", "").replace("\n", ""), tClass);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public SipMessage messageToObj(RequestEvent event) {
|
||||
try {
|
||||
Request request = event.getRequest();
|
||||
if ((!Request.MESSAGE.equals(request.getMethod())
|
||||
&& !Request.NOTIFY.equals(request.getMethod())
|
||||
&& !Request.SUBSCRIBE.equals(request.getMethod()))
|
||||
|| request.getRawContent() == null) {
|
||||
return null;
|
||||
}
|
||||
String content = new String(request.getRawContent(), "GB2312");
|
||||
JsonNode jsonNode = mapper.readTree(content);
|
||||
String cmdType = jsonNode.get("CmdType").asText();
|
||||
Function<String, SipMessage> converter = valueConverter.get(cmdType);
|
||||
if (null != converter) {
|
||||
return converter.apply(content);
|
||||
}
|
||||
} catch (Throwable error) {
|
||||
log.error("handle SIP message error \n{}", event.getRequest(), error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ClientTransaction transmitRequest(Request request) throws SipException {
|
||||
ClientTransaction clientTransaction = sipserver.getNewClientTransaction(request);
|
||||
clientTransaction.sendRequest();
|
||||
return clientTransaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void subscribe(@Nonnull SipDevice device, int startAlarmPriority, int endAlarmPriority, int expires, @Nonnull String alarmMethod, @Nullable Date startAlarmTime, @Nullable Date endAlarmTime) {
|
||||
String startAlarmTimeString = startAlarmTime == null ? "" : SipUtil.dateToISO8601(startAlarmTime);
|
||||
String endAlarmTimeString = endAlarmTime == null ? "" : SipUtil.dateToISO8601(endAlarmTime);
|
||||
ExpiresHeader expiresHeader = sipFactory.createHeaderFactory().createExpiresHeader(expires);
|
||||
EventHeader eventHeader = sipFactory.createHeaderFactory().createEventHeader("presemce");
|
||||
this.sendRequest(sn ->
|
||||
"<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n" +
|
||||
"<Query>\r\n" +
|
||||
"<CmdType>Alarm</CmdType>\r\n" +
|
||||
"<SN>" + sn + "</SN>\r\n" +
|
||||
"<DeviceID>" + device.getDeviceSipId() + "</DeviceID>\r\n" +
|
||||
"<StartAlarmPriority>" + startAlarmPriority + "</StartAlarmPriority>\n" +
|
||||
"<EndAlarmPriority>" + endAlarmPriority + "</EndAlarmPriority>\n" +
|
||||
"<AlarmMethod>" + alarmMethod + "</AlarmMethod>\n" +
|
||||
"<StartTime>" + startAlarmTimeString + "</StartTime>\n" +
|
||||
"<EndTime>" + endAlarmTimeString + "</EndTime>\n" +
|
||||
"</Query>\r\n",
|
||||
Request.SUBSCRIBE,
|
||||
device,
|
||||
null,
|
||||
"AK32B1U8DKDrA",
|
||||
null,
|
||||
expiresHeader,
|
||||
eventHeader
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deviceControl(SipDevice device, DeviceControl command) {
|
||||
this.sendRequest(sn -> command.toXml(sn, "GB2312"),
|
||||
Request.MESSAGE,
|
||||
device,
|
||||
"ViaPtzBranch",
|
||||
"FromPtzTag",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean deviceInfoQuery(SipDevice device) {
|
||||
this.sendRequest(sn ->
|
||||
"<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n" +
|
||||
"<Query>\r\n" +
|
||||
"<CmdType>DeviceInfo</CmdType>\r\n" +
|
||||
"<SN>" + sn + "</SN>\r\n" +
|
||||
"<DeviceID>" + device.getDeviceSipId() + "</DeviceID>\r\n" +
|
||||
"</Query>\r\n",
|
||||
Request.MESSAGE,
|
||||
device,
|
||||
"ViaDeviceInfoBranch",
|
||||
"FromDeviceInfoTag",
|
||||
"ToDeviceInfoTag"
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean catalogQuery(SipDevice device) {
|
||||
this.sendRequest(sn ->
|
||||
"<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n" +
|
||||
"<Query>\r\n" +
|
||||
"<CmdType>Catalog</CmdType>\r\n" +
|
||||
"<SN>" + sn + "</SN>\r\n" +
|
||||
"<DeviceID>" + device.getDeviceSipId() + "</DeviceID>\r\n" +
|
||||
"</Query>\r\n",
|
||||
Request.MESSAGE,
|
||||
device,
|
||||
"ViaCatalogBranch",
|
||||
"FromCatalogTag",
|
||||
null
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean recordInfoQuery(SipDevice device, String sn, String channelId, Date start, Date end) {
|
||||
String startTimeString = SipUtil.dateToISO8601(start);
|
||||
String endTimeString = SipUtil.dateToISO8601(end);
|
||||
;
|
||||
this.sendRequest("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n" +
|
||||
"<Query>\r\n" +
|
||||
"<CmdType>RecordInfo</CmdType>\r\n" +
|
||||
"<SN>" + sn + "</SN>\r\n" +
|
||||
"<DeviceID>" + channelId + "</DeviceID>\r\n" +
|
||||
"<StartTime>" + startTimeString + "</StartTime>\r\n" +
|
||||
"<EndTime>" + endTimeString + "</EndTime>\r\n" +
|
||||
"<Secrecy>0</Secrecy>\r\n" +
|
||||
"<Type>all</Type>\r\n" +
|
||||
"</Query>\r\n",
|
||||
Request.MESSAGE,
|
||||
device,
|
||||
"ViarecordInfoBranch",
|
||||
"FromrecordInfoTag",
|
||||
null
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
public <T> T getExecResult(String key, long timeout) {
|
||||
long time = 0;
|
||||
while (true) {
|
||||
try {
|
||||
T instance = redisCache.getCacheObject(key);
|
||||
if (null == instance) {
|
||||
if (time >= timeout) {
|
||||
log.error("key:{} get Response timeout", key);
|
||||
return null;
|
||||
}
|
||||
time += 1000;
|
||||
TimeUnit.MILLISECONDS.sleep(1000L);
|
||||
} else {
|
||||
return instance;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
log.error("key:{} can't get Response", key);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,186 @@
|
||||
package com.fastbee.sip.server.impl;
|
||||
|
||||
import com.fastbee.sip.server.RequestBuilder;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import javax.sip.SipFactory;
|
||||
import javax.sip.address.Address;
|
||||
import javax.sip.address.SipURI;
|
||||
import javax.sip.header.*;
|
||||
import javax.sip.message.Request;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class RequestBuilderImpl implements RequestBuilder {
|
||||
private SipFactory sipFactory;
|
||||
private String host;
|
||||
private int port;
|
||||
private String user;
|
||||
private String method;
|
||||
private boolean transportTcp;
|
||||
private long cSeq = 1L;
|
||||
private final List<ViaHeader> viaHeaders = new ArrayList<>();
|
||||
|
||||
private ContactHeader contactHeader;
|
||||
private SubjectHeader subjectHeader;
|
||||
private FromHeader fromHeader;
|
||||
private ToHeader toHeader;
|
||||
private AuthorizationHeader authorizationHeader;
|
||||
private ContentTypeHeader contentTypeHeader;
|
||||
private byte[] content;
|
||||
private SipURI requestLine;
|
||||
|
||||
public RequestBuilderImpl(SipFactory sipFactory) {
|
||||
this.sipFactory = sipFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public RequestBuilder requestLine(String sipId, String host, int port) {
|
||||
requestLine = sipFactory.createAddressFactory().createSipURI(sipId, host + ":" + port);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBuilder user(String user) {
|
||||
this.user = user;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBuilder method(String method) {
|
||||
this.method = method;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public RequestBuilder via(String host,
|
||||
int port,
|
||||
String transport,
|
||||
String viaTag) {
|
||||
this.port = port;
|
||||
this.transportTcp = "TCP".equals(transport);
|
||||
this.host = host;
|
||||
ViaHeader viaHeader = sipFactory.createHeaderFactory()
|
||||
.createViaHeader(host, port, transport, viaTag);
|
||||
viaHeader.setRPort();
|
||||
viaHeaders.add(viaHeader);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public RequestBuilder from(String sipId,
|
||||
String domain,
|
||||
String fromTag) {
|
||||
SipURI from = sipFactory.createAddressFactory().createSipURI(sipId, domain);
|
||||
Address fromAddress = sipFactory.createAddressFactory().createAddress(from);
|
||||
fromHeader = sipFactory.createHeaderFactory()
|
||||
.createFromHeader(fromAddress, fromTag);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public RequestBuilder to(String sipId,
|
||||
String domain,
|
||||
String toTag) {
|
||||
SipURI from = sipFactory.createAddressFactory().createSipURI(sipId, domain);
|
||||
Address fromAddress = sipFactory.createAddressFactory().createAddress(from);
|
||||
toHeader = sipFactory.createHeaderFactory()
|
||||
.createToHeader(fromAddress, toTag);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public RequestBuilder contact(String user, int port) {
|
||||
Address concatAddress = sipFactory.createAddressFactory()
|
||||
.createAddress(sipFactory.createAddressFactory()
|
||||
.createSipURI(user, user + ":" + port));
|
||||
contactHeader = sipFactory.createHeaderFactory().createContactHeader(concatAddress);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBuilder cSeq(int cSeq) {
|
||||
this.cSeq = cSeq;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public RequestBuilder subject(String subject) {
|
||||
subjectHeader = sipFactory.createHeaderFactory()
|
||||
.createSubjectHeader(subject);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public RequestBuilder contentxml(byte[] content) {
|
||||
contentTypeHeader = sipFactory.createHeaderFactory()
|
||||
.createContentTypeHeader("APPLICATION", "MANSCDP+xml");
|
||||
this.content = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public RequestBuilder contentsdp(byte[] content) {
|
||||
contentTypeHeader = sipFactory.createHeaderFactory()
|
||||
.createContentTypeHeader("APPLICATION", "SDP");
|
||||
this.content = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBuilder authorization(AuthorizationHeader header) {
|
||||
this.authorizationHeader = header;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public Request build(CallIdHeader callId) {
|
||||
//请求行
|
||||
SipURI requestLine = this.requestLine == null ? sipFactory.createAddressFactory()
|
||||
.createSipURI(user, host + ":" + port)
|
||||
: this.requestLine;
|
||||
|
||||
//callid
|
||||
CallIdHeader callIdHeader = callId;
|
||||
|
||||
//Forwards
|
||||
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
|
||||
|
||||
//ceq
|
||||
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(cSeq, method);
|
||||
Request request = sipFactory.createMessageFactory()
|
||||
.createRequest(requestLine, method, callIdHeader, cSeqHeader, fromHeader, toHeader, viaHeaders, maxForwards);
|
||||
//Authorization
|
||||
if (this.authorizationHeader != null) {
|
||||
request.addHeader(this.authorizationHeader);
|
||||
}
|
||||
//Contact
|
||||
if (contactHeader != null) {
|
||||
request.addHeader(contactHeader);
|
||||
}
|
||||
// Subject
|
||||
if (subjectHeader != null) {
|
||||
request.addHeader(subjectHeader);
|
||||
}
|
||||
//Content
|
||||
if (content != null) {
|
||||
request.setContent(content, contentTypeHeader);
|
||||
}
|
||||
|
||||
return request;
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package com.fastbee.sip.server.impl;
|
||||
|
||||
import com.fastbee.sip.domain.SipConfig;
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.server.IRtspCmd;
|
||||
import com.fastbee.sip.server.ReqMsgHeaderBuilder;
|
||||
import com.fastbee.sip.service.ISipConfigService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.ClientTransaction;
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.SipProvider;
|
||||
import javax.sip.message.Request;
|
||||
import java.text.ParseException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RtspCmdImpl implements IRtspCmd {
|
||||
public static Map<String, Long> CSEQCACHE = new ConcurrentHashMap<>();
|
||||
|
||||
@Autowired
|
||||
private ReqMsgHeaderBuilder headerBuilder;
|
||||
|
||||
@Autowired
|
||||
@Qualifier(value = "udpSipServer")
|
||||
private SipProvider sipserver;
|
||||
|
||||
@Autowired
|
||||
private ISipConfigService sipConfigService;
|
||||
|
||||
public void playPause(SipDevice device, String channelId, String streamId) {
|
||||
try {
|
||||
SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
|
||||
if (sipConfig == null) {
|
||||
log.error("[playPause] sipConfig is null");
|
||||
return ;
|
||||
}
|
||||
String content = "PAUSE RTSP/1.0\r\n" +
|
||||
"CSeq: " + getInfoCseq() + "\r\n" +
|
||||
"PauseTime: now\r\n";
|
||||
Request request = headerBuilder.createRtspRequest(device, sipConfig, channelId, streamId, content);
|
||||
ClientTransaction clientTransaction = sipserver.getNewClientTransaction(request);
|
||||
clientTransaction.sendRequest();
|
||||
|
||||
} catch (SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void playReplay(SipDevice device, String channelId, String streamId) {
|
||||
try {
|
||||
SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
|
||||
if (sipConfig == null) {
|
||||
log.error("[playReplay] sipConfig is null");
|
||||
return ;
|
||||
}
|
||||
String content = "PLAY RTSP/1.0\r\n" +
|
||||
"CSeq: " + getInfoCseq() + "\r\n" +
|
||||
"Range: npt=now-\r\n";
|
||||
Request request = headerBuilder.createRtspRequest(device, sipConfig, channelId, streamId, content);
|
||||
ClientTransaction clientTransaction = sipserver.getNewClientTransaction(request);
|
||||
clientTransaction.sendRequest();
|
||||
} catch (SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void playBackSeek(SipDevice device, String channelId, String streamId, long seektime) {
|
||||
try {
|
||||
SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
|
||||
if (sipConfig == null) {
|
||||
log.error("[playBackSeek] sipConfig is null");
|
||||
return ;
|
||||
}
|
||||
String content = "PLAY RTSP/1.0\r\n" +
|
||||
"CSeq: " + getInfoCseq() + "\r\n" +
|
||||
"Range: npt=" + Math.abs(seektime) + "-\r\n";
|
||||
Request request = headerBuilder.createRtspRequest(device, sipConfig, channelId, streamId, content);
|
||||
ClientTransaction clientTransaction = sipserver.getNewClientTransaction(request);
|
||||
clientTransaction.sendRequest();
|
||||
} catch (SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void playBackSpeed(SipDevice device, String channelId, String streamId, Integer speed) {
|
||||
try {
|
||||
SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
|
||||
if (sipConfig == null) {
|
||||
log.error("[playBackSpeed] sipConfig is null");
|
||||
return ;
|
||||
}
|
||||
String content = "PLAY RTSP/1.0\r\n" +
|
||||
"CSeq: " + getInfoCseq() + "\r\n" +
|
||||
"Scale: " + speed + ".000000\r\n";
|
||||
Request request = headerBuilder.createRtspRequest(device, sipConfig, channelId, streamId, content);
|
||||
ClientTransaction clientTransaction = sipserver.getNewClientTransaction(request);
|
||||
clientTransaction.sendRequest();
|
||||
} catch (SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setCseq(String streamId) {
|
||||
if (CSEQCACHE.containsKey(streamId)) {
|
||||
CSEQCACHE.put(streamId, CSEQCACHE.get(streamId) + 1);
|
||||
} else {
|
||||
CSEQCACHE.put(streamId, 2l);
|
||||
}
|
||||
}
|
||||
|
||||
private int getInfoCseq() {
|
||||
return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8));
|
||||
}
|
||||
}
|
@ -0,0 +1,381 @@
|
||||
package com.fastbee.sip.server.impl;
|
||||
|
||||
import com.fastbee.sip.domain.MediaServer;
|
||||
import com.fastbee.sip.domain.SipConfig;
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.enums.SessionType;
|
||||
import com.fastbee.sip.model.InviteInfo;
|
||||
import com.fastbee.sip.model.VideoSessionInfo;
|
||||
import com.fastbee.sip.server.ISipCmd;
|
||||
import com.fastbee.sip.server.ReqMsgHeaderBuilder;
|
||||
import com.fastbee.sip.server.VideoSessionManager;
|
||||
import com.fastbee.sip.service.IInviteService;
|
||||
import com.fastbee.sip.service.IMediaServerService;
|
||||
import com.fastbee.sip.service.ISipConfigService;
|
||||
import com.fastbee.sip.service.ISipDeviceService;
|
||||
import com.fastbee.sip.util.SipUtil;
|
||||
import com.fastbee.sip.util.ZlmApiUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.*;
|
||||
import javax.sip.message.Request;
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SipCmdImpl implements ISipCmd {
|
||||
|
||||
@Autowired
|
||||
private VideoSessionManager streamSession;
|
||||
|
||||
@Autowired
|
||||
private ReqMsgHeaderBuilder headerBuilder;
|
||||
|
||||
@Autowired
|
||||
private ISipConfigService sipConfigService;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private ISipDeviceService sipDeviceService;
|
||||
|
||||
@Autowired
|
||||
private ZlmApiUtils zlmApiUtils;
|
||||
|
||||
@Autowired
|
||||
private VideoSessionManager videoSessionManager;
|
||||
|
||||
@Autowired
|
||||
private IInviteService inviteService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier(value = "udpSipServer")
|
||||
private SipProvider sipserver;
|
||||
|
||||
@Override
|
||||
public VideoSessionInfo playStreamCmd(SipDevice device, String channelId, boolean record) {
|
||||
try {
|
||||
SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
|
||||
if (sipConfig == null) {
|
||||
log.error("playStreamCmd sipConfig is null");
|
||||
return null;
|
||||
}
|
||||
MediaServer mediaInfo = mediaServerService.selectMediaServerBydeviceSipId(device.getDeviceSipId());
|
||||
if (mediaInfo == null) {
|
||||
log.error("playStreamCmd mediaInfo is null");
|
||||
return null;
|
||||
}
|
||||
VideoSessionInfo info = VideoSessionInfo.builder()
|
||||
.mediaServerId(mediaInfo.getServerId())
|
||||
.deviceId(device.getDeviceSipId())
|
||||
.channelId(channelId)
|
||||
.streamMode(device.getStreammode().toUpperCase())
|
||||
.build();
|
||||
String fromTag;
|
||||
if (record) {
|
||||
info.setType(SessionType.playrecord);
|
||||
fromTag = "playrecord";
|
||||
} else {
|
||||
info.setType(SessionType.play);
|
||||
fromTag = "play";
|
||||
}
|
||||
//创建rtp服务器
|
||||
info = mediaServerService.createRTPServer(sipConfig, mediaInfo, device, info);
|
||||
//创建Invite会话
|
||||
String content = buildRequestContent(sipConfig, mediaInfo, info);
|
||||
Request request = headerBuilder.createInviteRequest(device, sipConfig, channelId, content, info.getSsrc(), fromTag);
|
||||
//发送消息
|
||||
ClientTransaction transaction = transmitRequest(request);
|
||||
log.info("playStreamCmd streamSession: {}", info);
|
||||
InviteInfo invite = InviteInfo.builder()
|
||||
.ssrc(info.getSsrc())
|
||||
.fromTag(fromTag)
|
||||
.callId(transaction.getDialog().getCallId().getCallId())
|
||||
.port(info.getPort()).build();
|
||||
log.warn("playStreamCmd invite: {}", invite);
|
||||
inviteService.updateInviteInfo(info, invite);
|
||||
streamSession.put(info, transaction);
|
||||
return info;
|
||||
} catch (SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoSessionInfo playbackStreamCmd(SipDevice device, String channelId, String startTime, String endTime) {
|
||||
try {
|
||||
SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
|
||||
if (sipConfig == null) {
|
||||
log.error("playbackStreamCmd sipConfig is null");
|
||||
return null;
|
||||
}
|
||||
MediaServer mediaInfo = mediaServerService.selectMediaServerBydeviceSipId(device.getDeviceSipId());
|
||||
if (mediaInfo == null) {
|
||||
log.error("playbackStreamCmd mediaInfo is null");
|
||||
return null;
|
||||
}
|
||||
VideoSessionInfo info = VideoSessionInfo.builder()
|
||||
.mediaServerId(mediaInfo.getServerId())
|
||||
.deviceId(device.getDeviceSipId())
|
||||
.channelId(channelId)
|
||||
.streamMode(device.getStreammode().toUpperCase())
|
||||
.type(SessionType.playback)
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.build();
|
||||
//创建rtp服务器
|
||||
info = mediaServerService.createRTPServer(sipConfig, mediaInfo, device, info);
|
||||
//创建Invite会话
|
||||
String fromTag = "playback" + SipUtil.getNewFromTag();
|
||||
String viaTag = SipUtil.getNewViaTag();
|
||||
String content = buildRequestContent(sipConfig, mediaInfo, info);
|
||||
Request request = headerBuilder.createPlaybackInviteRequest(device, sipConfig, channelId, content, viaTag, fromTag);
|
||||
//发送消息
|
||||
ClientTransaction transaction = transmitRequest(request);
|
||||
log.info("playbackStreamCmd streamSession: {}", info);
|
||||
InviteInfo invite = InviteInfo.builder()
|
||||
.ssrc(info.getSsrc())
|
||||
.fromTag(fromTag)
|
||||
.viaTag(viaTag)
|
||||
.callId(transaction.getDialog().getCallId().getCallId())
|
||||
.port(info.getPort()).build();
|
||||
log.warn("playbackStreamCmd invite: {}", invite);
|
||||
inviteService.updateInviteInfo(info, invite);
|
||||
streamSession.put(info, transaction);
|
||||
return info;
|
||||
} catch (SipException | ParseException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoSessionInfo downloadStreamCmd(SipDevice device, String channelId,
|
||||
String startTime, String endTime, int downloadSpeed) {
|
||||
try {
|
||||
SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
|
||||
if (sipConfig == null) {
|
||||
log.error("downloadStreamCmd sipConfig is null");
|
||||
return null;
|
||||
}
|
||||
MediaServer mediaInfo = mediaServerService.selectMediaServerBydeviceSipId(device.getDeviceSipId());
|
||||
if (mediaInfo == null) {
|
||||
log.error("downloadStreamCmd mediaInfo is null");
|
||||
return null;
|
||||
}
|
||||
VideoSessionInfo info = VideoSessionInfo.builder()
|
||||
.mediaServerId(mediaInfo.getServerId())
|
||||
.deviceId(device.getDeviceSipId())
|
||||
.channelId(channelId)
|
||||
.streamMode(device.getStreammode().toUpperCase())
|
||||
.type(SessionType.download)
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.downloadSpeed(downloadSpeed)
|
||||
.build();
|
||||
;
|
||||
//创建rtp服务器
|
||||
info = mediaServerService.createRTPServer(sipConfig, mediaInfo, device, info);
|
||||
//创建Invite会话
|
||||
String fromTag = "download" + SipUtil.getNewFromTag();;
|
||||
String viaTag = SipUtil.getNewViaTag();
|
||||
String content = buildRequestContent(sipConfig, mediaInfo, info);
|
||||
Request request = headerBuilder.createPlaybackInviteRequest(device, sipConfig, channelId, content, viaTag, fromTag);
|
||||
//发送消息
|
||||
ClientTransaction transaction = transmitRequest(request);
|
||||
log.info("downloadStreamCmd streamSession: {}", info);
|
||||
InviteInfo invite = InviteInfo.builder()
|
||||
.ssrc(info.getSsrc())
|
||||
.fromTag(fromTag)
|
||||
.viaTag(viaTag)
|
||||
.callId(transaction.getDialog().getCallId().getCallId())
|
||||
.port(info.getPort()).build();
|
||||
log.warn("downloadStreamCmd invite: {}", invite);
|
||||
inviteService.updateInviteInfo(info, invite);
|
||||
streamSession.put(info, transaction);
|
||||
return info;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void streamByeCmd(SipDevice device, String channelId, String stream, String ssrc) {
|
||||
SipConfig sipConfig = sipConfigService.selectSipConfigBydeviceSipId(device.getDeviceSipId());
|
||||
if (sipConfig == null) {
|
||||
log.error("[发送BYE] sipConfig is null");
|
||||
return;
|
||||
}
|
||||
MediaServer mediaInfo = mediaServerService.selectMediaServerBydeviceSipId(device.getDeviceSipId());
|
||||
if (mediaInfo == null) {
|
||||
log.error("[发送BYE] mediaInfo is null");
|
||||
return;
|
||||
}
|
||||
List<VideoSessionInfo> SessionInfoList = streamSession.getSessionInfoForAll(device.getDeviceSipId(), channelId, stream, ssrc);
|
||||
if (SessionInfoList == null || SessionInfoList.isEmpty()) {
|
||||
log.warn("[发送BYE] 未找到事务信息,设备: device: {}, channel: {}", device.getDeviceSipId(), channelId);
|
||||
return;
|
||||
}
|
||||
for (VideoSessionInfo info : SessionInfoList) {
|
||||
try {
|
||||
log.warn("[发送BYE] 设备: device: {}, channel: {}, stream: {}, ssrc: {}", device.getDeviceSipId(),
|
||||
info.getChannelId(), info.getStream(), info.getSsrc());
|
||||
List<InviteInfo> list = inviteService.getInviteInfoAll(info.getType(), info.getDeviceId(), info.getChannelId(), info.getStream());
|
||||
if (list.isEmpty()) {
|
||||
log.warn("[发送BYE] 未找到invite信息,设备: Stream: {}", info.getStream());
|
||||
} else {
|
||||
for (InviteInfo invite : list) {
|
||||
// 发送bye消息
|
||||
Request request = headerBuilder.createByeRequest(device, sipConfig, channelId, invite);
|
||||
//获取缓存会话
|
||||
ClientTransaction transaction = videoSessionManager.getclientTransaction(info);
|
||||
if (transaction == null) {
|
||||
log.warn("[发送BYE] transaction is null");
|
||||
continue;
|
||||
}
|
||||
Dialog dialog = transaction.getDialog();
|
||||
if (dialog == null) {
|
||||
log.warn("[发送BYE] transaction is dialog");
|
||||
continue;
|
||||
}
|
||||
//创建客户端,发送请求
|
||||
ClientTransaction clientTransaction = sipserver.getNewClientTransaction(request);
|
||||
dialog.sendRequest(clientTransaction);
|
||||
// 释放ssrc
|
||||
SipUtil.releaseSsrc(info.getSsrc());
|
||||
// 关闭rtp服务器
|
||||
zlmApiUtils.closeRTPServer(mediaInfo, stream);
|
||||
log.warn("closeRTPServer Port:{}", info.getPort());
|
||||
if (info.isPushing()) {
|
||||
info.setPushing(false);
|
||||
}
|
||||
if (info.isRecording()) {
|
||||
info.setPushing(false);
|
||||
}
|
||||
streamSession.put(info, null);
|
||||
// 删除会话缓存
|
||||
streamSession.remove(info.getDeviceId(), info.getChannelId(), stream, info.getSsrc());
|
||||
// 删除invite缓存
|
||||
inviteService.removeInviteInfo(info.getType(), info.getDeviceId(), info.getChannelId(), info.getStream());
|
||||
}
|
||||
}
|
||||
} catch (ParseException | SipException | InvalidArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamByeCmd(String deviceId, String channelId, String stream, String ssrc) {
|
||||
SipDevice dev = sipDeviceService.selectSipDeviceBySipId(deviceId);
|
||||
if (dev == null) {
|
||||
log.error("[发送BYE] device is null");
|
||||
return;
|
||||
}
|
||||
streamByeCmd(dev, channelId, stream, ssrc);
|
||||
}
|
||||
|
||||
private ClientTransaction transmitRequest(Request request) throws SipException {
|
||||
log.info("transmitRequest:{}", request);
|
||||
ClientTransaction clientTransaction = sipserver.getNewClientTransaction(request);
|
||||
clientTransaction.sendRequest();
|
||||
return clientTransaction;
|
||||
}
|
||||
|
||||
private String buildRequestContent(SipConfig sipConfig, MediaServer mediaInfo, VideoSessionInfo info) {
|
||||
String streamMode = info.getStreamMode();
|
||||
StringBuilder content = new StringBuilder(200);
|
||||
content.append("v=0\r\n");
|
||||
switch (info.getType()) {
|
||||
case play:
|
||||
content.append("o=").append(info.getChannelId()).append(" 0 0 IN IP4 ").append(mediaInfo.getIp()).append("\r\n");
|
||||
content.append("s=Play\r\n");
|
||||
content.append("c=IN IP4 ").append(mediaInfo.getIp()).append("\r\n");
|
||||
content.append("t=0 0\r\n");
|
||||
break;
|
||||
case playrecord:
|
||||
content.append("o=").append(info.getChannelId()).append(" 0 0 IN IP4 ").append(mediaInfo.getIp()).append("\r\n");
|
||||
content.append("s=Play\r\n");
|
||||
content.append("c=IN IP4 ").append(mediaInfo.getIp()).append("\r\n");
|
||||
content.append("t=0 0\r\n");
|
||||
break;
|
||||
case playback:
|
||||
content.append("o=").append(info.getChannelId()).append(" 0 0 IN IP4 ").append(mediaInfo.getIp()).append("\r\n");
|
||||
content.append("s=Playback\r\n");
|
||||
content.append("u=").append(info.getChannelId()).append(":0\r\n");
|
||||
content.append("c=IN IP4 ").append(mediaInfo.getIp()).append("\r\n");
|
||||
content.append("t=").append(info.getStartTime()).append(" ").append(info.getEndTime()).append("\r\n");
|
||||
break;
|
||||
case download:
|
||||
content.append("o=").append(info.getChannelId()).append(" 0 0 IN IP4 ").append(mediaInfo.getIp()).append("\r\n");
|
||||
content.append("s=Download\r\n");
|
||||
content.append("u=").append(info.getChannelId()).append(":0\r\n");
|
||||
content.append("c=IN IP4 ").append(mediaInfo.getIp()).append("\r\n");
|
||||
content.append("t=").append(info.getStartTime()).append(" ").append(info.getEndTime()).append("\r\n");
|
||||
break;
|
||||
}
|
||||
if (sipConfig.getSeniorsdp() != null && sipConfig.getSeniorsdp() == 1) {
|
||||
if ("TCP-PASSIVE".equals(streamMode)) {
|
||||
content.append("m=video ").append(info.getPort()).append(" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
} else if ("TCP-ACTIVE".equals(streamMode)) {
|
||||
content.append("m=video ").append(info.getPort()).append(" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
} else if ("UDP".equals(streamMode)) {
|
||||
content.append("m=video ").append(info.getPort()).append(" 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");
|
||||
content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
|
||||
content.append("a=rtpmap:126 H264/90000\r\n");
|
||||
content.append("a=rtpmap:125 H264S/90000\r\n");
|
||||
content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
|
||||
content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
|
||||
content.append("a=fmtp:99 profile-level-id=3\r\n");
|
||||
content.append("a=rtpmap:98 H264/90000\r\n");
|
||||
content.append("a=rtpmap:97 MPEG4/90000\r\n");
|
||||
if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式
|
||||
content.append("a=setup:passive\r\n");
|
||||
content.append("a=connection:new\r\n");
|
||||
} else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
|
||||
content.append("a=setup:active\r\n");
|
||||
content.append("a=connection:new\r\n");
|
||||
}
|
||||
} else {
|
||||
switch (streamMode) {
|
||||
case "TCP-PASSIVE":
|
||||
content.append("m=video ").append(info.getPort()).append(" TCP/RTP/AVP 96 97 98 99\r\n");
|
||||
break;
|
||||
case "TCP-ACTIVE":
|
||||
content.append("m=video ").append(info.getPort()).append(" TCP/RTP/AVP 96 97 98 99\r\n");
|
||||
break;
|
||||
case "UDP":
|
||||
//content.append("m=video ").append(info.getPort()).append(" RTP/AVP 96 97 98 99\r\n");
|
||||
content.append("m=video ").append(info.getPort()).append(" RTP/AVP 96 97 98\r\n");
|
||||
break;
|
||||
}
|
||||
content.append("a=recvonly\r\n");
|
||||
content.append("a=rtpmap:96 PS/90000\r\n");
|
||||
content.append("a=rtpmap:97 MPEG4/90000\r\n");
|
||||
content.append("a=rtpmap:98 H264/90000\r\n");
|
||||
//content.append("a=rtpmap:99 H265/90000\r\n");
|
||||
if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式
|
||||
content.append("a=setup:passive\r\n");
|
||||
content.append("a=connection:new\r\n");
|
||||
} else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
|
||||
content.append("a=setup:active\r\n");
|
||||
content.append("a=connection:new\r\n");
|
||||
}
|
||||
}
|
||||
if (info.getType() == SessionType.download) {
|
||||
content.append("a=downloadspeed:").append(info.getDownloadSpeed()).append("\r\n");
|
||||
}
|
||||
content.append("y=").append(info.getSsrc()).append("\r\n");// ssrc
|
||||
return content.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package com.fastbee.sip.server.msg;
|
||||
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import com.fastbee.sip.enums.AlarmMethod;
|
||||
import com.fastbee.sip.enums.AlarmType;
|
||||
import com.fastbee.sip.server.SipMessage;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class Alarm implements SipMessage {
|
||||
@JacksonXmlProperty(localName = "DeviceID")
|
||||
private String deviceId;
|
||||
|
||||
@JacksonXmlProperty(localName = "AlarmPriority")
|
||||
private String alarmPriority;
|
||||
|
||||
@JacksonXmlProperty(localName = "AlarmTime")
|
||||
private String alarmTime;
|
||||
|
||||
@JacksonXmlProperty(localName = "AlarmMethod")
|
||||
private AlarmMethod alarmMethod;
|
||||
|
||||
@JacksonXmlProperty(localName = "Longitude")
|
||||
private Float longitude;
|
||||
|
||||
@JacksonXmlProperty(localName = "Latitude")
|
||||
private Float latitude;
|
||||
|
||||
@JacksonXmlProperty(localName = "AlarmDescription")
|
||||
private String description;
|
||||
|
||||
@JacksonXmlProperty(localName = "Info")
|
||||
private Info info;
|
||||
|
||||
@JacksonXmlProperty(localName = "SN")
|
||||
private String sn;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class Info {
|
||||
|
||||
@JacksonXmlProperty(localName = "AlarmType")
|
||||
private String alarmType;
|
||||
|
||||
@JacksonXmlProperty(localName = "AlarmTypeParam")
|
||||
private AlarmTypeParam alarmTypeParam;
|
||||
|
||||
public Optional<AlarmType> getAlarmTypeEnum(AlarmMethod method) {
|
||||
return AlarmType.of(method, alarmType);
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class AlarmTypeParam {
|
||||
//1-进入区域;2-离开区域
|
||||
@JacksonXmlProperty(localName = "EventType")
|
||||
private String eventType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceId() {
|
||||
return this.deviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSn() {
|
||||
return this.sn;
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package com.fastbee.sip.server.msg;
|
||||
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import com.fastbee.sip.model.GB28181DeviceChannel;
|
||||
import com.fastbee.sip.server.SipMessage;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.fastbee.sip.util.SipUtil.safeString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class CatalogInfo implements SipMessage {
|
||||
@JacksonXmlProperty(localName = "DeviceID")
|
||||
private String deviceId;
|
||||
|
||||
@JacksonXmlProperty(localName = "SN")
|
||||
private String sn;
|
||||
|
||||
@JacksonXmlProperty(localName = "SumNum")
|
||||
private String _sumNum;
|
||||
|
||||
@JacksonXmlProperty(localName = "DeviceList")
|
||||
private List<GB28181DeviceChannel> channelList;
|
||||
|
||||
@Override
|
||||
public String getDeviceId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSn() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int totalPart() {
|
||||
return getSumNum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numberOfPart() {
|
||||
return channelList == null ? 0 : channelList.size();
|
||||
}
|
||||
|
||||
public int getSumNum() {
|
||||
return _sumNum == null ? 0 : Integer.parseInt(_sumNum);
|
||||
}
|
||||
|
||||
public void setSumNum(int sumNum) {
|
||||
this._sumNum = String.valueOf(sumNum);
|
||||
}
|
||||
|
||||
public String toXml(String charset) {
|
||||
StringBuilder body = new StringBuilder("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\n" +
|
||||
"<Response>\n" +
|
||||
"<CmdType>Catalog</CmdType>\n" +
|
||||
"<SN>" + getSn() + "</SN>\n" +
|
||||
"<DeviceID>" + getDeviceId() + "</DeviceID>\n" +
|
||||
"<Result>OK</Result>\n" +
|
||||
"<SumNum>" + getSumNum() + "</SumNum>\n" +
|
||||
"<DeviceList Num=\"" + getChannelList().size() + "\">");
|
||||
|
||||
for (GB28181DeviceChannel channel : getChannelList()) {
|
||||
|
||||
body
|
||||
.append("<Item>\n")
|
||||
.append("<DeviceID>").append(channel.getChannelId()).append("</DeviceID>\n")
|
||||
.append("<Name>").append(safeString(channel.getName())).append("</Name>\n")
|
||||
.append("<Manufacturer>").append(safeString(channel.getManufacturer())).append("</Manufacturer>\n")
|
||||
.append("<Model>").append(safeString(channel.getModel())).append("</Model>\n")
|
||||
.append("<Owner>").append(safeString(channel.getOwner())).append("</Owner>\n")
|
||||
.append("<CivilCode>").append(safeString(channel.getCivilCode())).append("</CivilCode>\n")
|
||||
.append("<Block>").append(safeString(channel.getBlock())).append("</Block>\n")
|
||||
.append("<Address>").append(safeString(channel.getAddress())).append("</Address>\n")
|
||||
.append("<Parental>").append(safeString(channel.getParental())).append("</Parental>\n")
|
||||
.append("<ParentID>").append(safeString(channel.getParentId())).append("</ParentID>\n")
|
||||
.append("<SafetyWay>").append(safeString(channel.getSafetyWay())).append("</SafetyWay>\n")
|
||||
.append("<RegisterWay>").append(safeString(channel.getRegisterWay())).append("</RegisterWay>\n")
|
||||
.append("<CertNum>").append(safeString(channel.getCertNum())).append("</CertNum>\n")
|
||||
.append("<Certifiable>").append(safeString(channel.getCertifiable())).append("</Certifiable>\n")
|
||||
.append("<ErrCode>").append(safeString(channel.getErrCode())).append("</ErrCode>\n")
|
||||
.append("<EndTime>").append(safeString(channel.getEndTime())).append("</EndTime>\n")
|
||||
.append("<Secrecy>").append(safeString(channel.getSecrecy())).append("</Secrecy>\n")
|
||||
.append("<IPAddress>").append(safeString(channel.getIpAddress())).append("</IPAddress>\n")
|
||||
.append("<Port>").append(safeString(channel.getPort())).append("</Port>\n")
|
||||
.append("<Password>").append(safeString(channel.getPassword())).append("</Password>\n")
|
||||
.append("<Status>").append(safeString(channel.getStatus().getCode())).append("</Status>\n")
|
||||
.append("<Longitude>").append(safeString(channel.getLongitude())).append("</Longitude>\n")
|
||||
.append("<Latitude>").append(safeString(channel.getLatitude())).append("</Latitude>\n");
|
||||
if (channel.getInfo() != null) {
|
||||
body.append("<Info>")
|
||||
.append(channel.getInfo().toXML())
|
||||
.append("</Info>\n");
|
||||
}
|
||||
|
||||
body.append("</Item>\n");
|
||||
}
|
||||
body.append("</DeviceList>\n</Response>");
|
||||
return body.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package com.fastbee.sip.server.msg;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import com.fastbee.sip.server.SipMessage;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ConfigDownload implements SipMessage {
|
||||
@JacksonXmlProperty(localName = "DeviceID")
|
||||
private String deviceId;
|
||||
|
||||
@JacksonXmlProperty(localName = "SN")
|
||||
private String sn;
|
||||
|
||||
@JacksonXmlProperty(localName = "ConfigType")
|
||||
private String configType;
|
||||
|
||||
@JacksonXmlProperty(localName = "BasicParam")
|
||||
private BasicParam basicParam;
|
||||
|
||||
@JacksonXmlProperty(localName = "VideoParamOp")
|
||||
private VideoParamOp videoParamOp;
|
||||
|
||||
public enum ConfigType {
|
||||
BasicParam,
|
||||
VideoParamOpt,
|
||||
SVACEncodeConfig,
|
||||
SVACDecodeConfig
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class BasicParam {
|
||||
|
||||
@JacksonXmlProperty(localName = "Name")
|
||||
private String name;
|
||||
|
||||
//注册过期时间
|
||||
@JacksonXmlProperty(localName = "Expiration")
|
||||
private String expiration;
|
||||
|
||||
//心跳间隔时间
|
||||
@JacksonXmlProperty(localName = "HeartBeatInterval")
|
||||
private int heartBeatInterval;
|
||||
|
||||
//心跳超时次数
|
||||
@JacksonXmlProperty(localName = "HeartBeatCount")
|
||||
private int heartBeatCount = 5;
|
||||
|
||||
//定位功能支持情况,取值:0-不支持;1-支持 GPS定位;2-支持北斗定位(可选, 默认取值为0)
|
||||
@JacksonXmlProperty(localName = "PositionCapability")
|
||||
private int positionCapability;
|
||||
|
||||
//经度
|
||||
@JacksonXmlProperty(localName = "Longitude")
|
||||
private float longitude;
|
||||
|
||||
//纬度
|
||||
@JacksonXmlProperty(localName = "Latitude")
|
||||
private float latitude;
|
||||
|
||||
public String toXml() {
|
||||
StringJoiner joiner = new StringJoiner("\n");
|
||||
joiner.add("<Name>" + name + "</Name>");
|
||||
joiner.add("<Expiration>" + expiration + "</Expiration>");
|
||||
joiner.add("<HeartBeatInterval>" + heartBeatInterval + "</HeartBeatInterval>");
|
||||
joiner.add("<HeartBeatCount>" + heartBeatCount + "</HeartBeatCount>");
|
||||
joiner.add("<PositionCapability>" + positionCapability + "</PositionCapability>");
|
||||
joiner.add("<Longitude>" + longitude + "</Longitude>");
|
||||
joiner.add("<Latitude>" + latitude + "</Latitude>");
|
||||
return joiner.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class VideoParamOp {
|
||||
|
||||
@JacksonXmlProperty(localName = "DownloadSpeed")
|
||||
private String downloadSpeed;
|
||||
|
||||
@JacksonXmlProperty(localName = "Resolution")
|
||||
private String resolution;
|
||||
|
||||
}
|
||||
|
||||
public String toXml(int sn, String charset) {
|
||||
StringJoiner joiner = new StringJoiner("\r\n");
|
||||
joiner.add("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>");
|
||||
joiner.add("<Query>");
|
||||
joiner.add("<CmdType>ConfigDownload</CmdType>");
|
||||
joiner.add("<SN>" + sn + "</SN>");
|
||||
joiner.add("<DeviceID>" + deviceId + "</DeviceID>");
|
||||
|
||||
if (configTypeIs(ConfigType.BasicParam) && getBasicParam() != null) {
|
||||
joiner.add("<BasicParam>" + getBasicParam().toXml() + "</BasicParam>");
|
||||
}
|
||||
|
||||
joiner.add("<Info></Info>");
|
||||
|
||||
joiner.add("</Query>");
|
||||
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this, SerializerFeature.PrettyFormat);
|
||||
}
|
||||
|
||||
public boolean configTypeIs(ConfigType type) {
|
||||
return type.name().equals(configType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSn() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
package com.fastbee.sip.server.msg;
|
||||
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import com.fastbee.sip.enums.Direct;
|
||||
import com.fastbee.sip.server.SipMessage;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class DeviceControl implements SipMessage {
|
||||
@JacksonXmlProperty(localName = "DeviceID")
|
||||
private String deviceId;
|
||||
|
||||
@JacksonXmlProperty(localName = "SN")
|
||||
private String sn;
|
||||
|
||||
@JacksonXmlProperty(localName = "PTZCmd")
|
||||
private String ptzCmd;
|
||||
|
||||
@JacksonXmlProperty(localName = "RecordCmd")
|
||||
private String recordCmd;
|
||||
|
||||
@JacksonXmlProperty(localName = "GuardCmd")
|
||||
private String guardCmd;
|
||||
|
||||
@JacksonXmlProperty(localName = "AlarmCmd")
|
||||
private String alarmCmd;
|
||||
|
||||
@JacksonXmlProperty(localName = "IFameCmd")
|
||||
private String iFameCmd;
|
||||
|
||||
@JacksonXmlProperty(localName = "DragZoomIn")
|
||||
private DragZoom dragZoomIn;
|
||||
|
||||
@JacksonXmlProperty(localName = "DragZoomOut")
|
||||
private DragZoom dragZoomOut;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class DragZoom {
|
||||
//播放窗口长度像素值
|
||||
@JacksonXmlProperty(localName = "Length")
|
||||
private int length;
|
||||
|
||||
//播放窗口宽度像素值
|
||||
@JacksonXmlProperty(localName = "Width")
|
||||
private int width;
|
||||
|
||||
//拉框中心的横轴坐标像素值
|
||||
@JacksonXmlProperty(localName = "MidPointX")
|
||||
private int midPointX;
|
||||
|
||||
//拉框中心的纵轴坐标像素值
|
||||
@JacksonXmlProperty(localName = "MidPointY")
|
||||
private int midPointY;
|
||||
|
||||
//拉框长度像素值
|
||||
@JacksonXmlProperty(localName = "LengthX")
|
||||
private int lengthX;
|
||||
|
||||
//拉框宽度像素值
|
||||
@JacksonXmlProperty(localName = "LengthY")
|
||||
private int lengthY;
|
||||
|
||||
}
|
||||
|
||||
//看守位控制命令
|
||||
@Getter
|
||||
@Setter
|
||||
public static class HomePosition {
|
||||
|
||||
//看守位使能1:开启,0:关闭
|
||||
@JacksonXmlProperty(localName = "Enabled")
|
||||
private int enabled;
|
||||
|
||||
//自动归位时间间隔,开启看守位时使用,单位:秒(s)
|
||||
@JacksonXmlProperty(localName = "ResetTime")
|
||||
private Integer resetTime;
|
||||
|
||||
//调用预置位编号,开启看守位时使用,取值范围0~255
|
||||
@JacksonXmlProperty(localName = "PresetIndex")
|
||||
private Integer presetIndex;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class AlarmCmdInfo {
|
||||
|
||||
//复位报警的报警方式属性
|
||||
@JacksonXmlProperty(localName = "AlarmMethod")
|
||||
private String alarmMethod;
|
||||
|
||||
@JacksonXmlProperty(localName = "AlarmType")
|
||||
private String alarmType;
|
||||
}
|
||||
|
||||
public DeviceControl setPtzDirect(Map<Direct, Integer> directAndSpeed) {
|
||||
int code = 0;
|
||||
StringBuilder cmd = new StringBuilder("A50F4D");
|
||||
for (Map.Entry<Direct, Integer> entry : directAndSpeed.entrySet()) {
|
||||
code = entry.getKey().merge(code);
|
||||
}
|
||||
//控制码
|
||||
cmd.append(String.format("%02X", code), 0, 2);
|
||||
//水平控制速度
|
||||
int lrSpeed = directAndSpeed.getOrDefault(Direct.LEFT, directAndSpeed.getOrDefault(Direct.RIGHT, 0));
|
||||
cmd.append(String.format("%02X", lrSpeed), 0, 2);
|
||||
//垂直控制速度
|
||||
int udSpeed = directAndSpeed.getOrDefault(Direct.UP, directAndSpeed.getOrDefault(Direct.DOWN, 0));
|
||||
cmd.append(String.format("%02X", udSpeed), 0, 2);
|
||||
//缩放控制速度
|
||||
int zoomSpeed = directAndSpeed.getOrDefault(Direct.ZOOM_IN, directAndSpeed.getOrDefault(Direct.ZOOM_OUT, 0)) & 0xF;
|
||||
cmd.append(String.format("%X", zoomSpeed), 0, 1)
|
||||
.append("0");
|
||||
|
||||
//校验码
|
||||
int checkCode = (0XA5 + 0X0F + 0X4D + code + lrSpeed + udSpeed + (zoomSpeed << 4)) % 256;
|
||||
cmd.append(String.format("%02X", checkCode), 0, 2);
|
||||
setPtzCmd(cmd.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toXml(int sn, String charset) {
|
||||
StringJoiner joiner = new StringJoiner("\n");
|
||||
joiner.add("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>");
|
||||
joiner.add("<Control>");
|
||||
joiner.add("<CmdType>DeviceControl</CmdType>");
|
||||
joiner.add("<SN>" + sn + "</SN>");
|
||||
joiner.add("<DeviceID>" + deviceId + "</DeviceID>");
|
||||
|
||||
if (isPtzControl()) {
|
||||
joiner.add("<PTZCmd>" + getPtzCmd() + "</PTZCmd>");
|
||||
}
|
||||
|
||||
joiner.add("<Info>");
|
||||
joiner.add("<ControlPriority>10</ControlPriority>");
|
||||
joiner.add("</Info>");
|
||||
joiner.add("</Control>");
|
||||
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSn() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isPtzControl() {
|
||||
return StringUtils.hasText(ptzCmd);
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package com.fastbee.sip.server.msg;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fastbee.sip.server.SipMessage;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class GB28181Device implements SipMessage {
|
||||
@JsonProperty("DeviceID")
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 设备名
|
||||
*/
|
||||
@JsonProperty("DeviceName")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 生产厂商
|
||||
*/
|
||||
@JsonProperty("Manufacturer")
|
||||
private String manufacturer;
|
||||
|
||||
/**
|
||||
* 型号
|
||||
*/
|
||||
@JsonProperty("Model")
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
@JsonProperty("Firmware")
|
||||
private String firmware;
|
||||
|
||||
/**
|
||||
* 传输协议
|
||||
* UDP/TCP
|
||||
*/
|
||||
private String transport;
|
||||
|
||||
/**
|
||||
* 数据流传输模式
|
||||
*/
|
||||
private StreamMode streamMode = StreamMode.UDP;
|
||||
|
||||
/**
|
||||
* 访问地址
|
||||
*/
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* 访问端口
|
||||
*/
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* 是否在线
|
||||
*/
|
||||
private boolean online;
|
||||
|
||||
@JsonProperty("Channel")
|
||||
private int channelNumber;
|
||||
|
||||
/**
|
||||
* 通道列表
|
||||
*/
|
||||
private List<String> channelList;
|
||||
|
||||
@JsonProperty("SN")
|
||||
private String sn;
|
||||
|
||||
/**
|
||||
* 心跳间隔
|
||||
*/
|
||||
private long heartBeatInterval = 300;
|
||||
|
||||
@Override
|
||||
public String getDeviceId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSn() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public enum StreamMode {
|
||||
UDP,
|
||||
TCP_ACTIVE,//主动模式
|
||||
TCP_PASSIVE//被动模式
|
||||
}
|
||||
|
||||
public String getHostAndPort() {
|
||||
return getHost() + ":" + getPort();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.fastbee.sip.server.msg;
|
||||
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import com.fastbee.sip.server.SipMessage;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class KeepaliveMessage implements SipMessage {
|
||||
@JacksonXmlProperty(localName = "DeviceID")
|
||||
private String deviceId;
|
||||
|
||||
@JacksonXmlProperty(localName = "Status")
|
||||
private String status;
|
||||
|
||||
@JacksonXmlProperty(localName = "SN")
|
||||
private String sn;
|
||||
|
||||
@Override
|
||||
public String getDeviceId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSn() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.fastbee.sip.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IGatewayService {
|
||||
void sendFunction(String deviceID,List<ThingsModelSimpleItem> functinos);
|
||||
void sendFunction(String deviceID,String identifier,String value);
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.fastbee.sip.service;
|
||||
|
||||
import com.fastbee.sip.enums.SessionType;
|
||||
import com.fastbee.sip.model.InviteInfo;
|
||||
import com.fastbee.sip.model.VideoSessionInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IInviteService {
|
||||
|
||||
void updateInviteInfo(VideoSessionInfo sinfo, InviteInfo inviteInfo);
|
||||
|
||||
InviteInfo getInviteInfo(SessionType type,
|
||||
String deviceId,
|
||||
String channelId,
|
||||
String stream);
|
||||
|
||||
List<InviteInfo> getInviteInfoAll(SessionType type, String deviceId, String channelId, String stream);
|
||||
|
||||
InviteInfo getInviteInfoBySSRC(String ssrc);
|
||||
|
||||
void removeInviteInfo(SessionType type,
|
||||
String deviceId,
|
||||
String channelId,
|
||||
String stream);
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package com.fastbee.sip.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fastbee.sip.domain.MediaServer;
|
||||
import com.fastbee.sip.domain.SipConfig;
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.model.VideoSessionInfo;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流媒体服务器配置Service接口
|
||||
*
|
||||
* @author zhuangpeng.li
|
||||
* @date 2022-11-30
|
||||
*/
|
||||
public interface IMediaServerService
|
||||
{
|
||||
/**
|
||||
* 查询流媒体服务器配置
|
||||
*
|
||||
* @param id 流媒体服务器配置主键
|
||||
* @return 流媒体服务器配置
|
||||
*/
|
||||
public MediaServer selectMediaServerById(Long id);
|
||||
/**
|
||||
* 查询流媒体服务器配置
|
||||
*
|
||||
* @return 流媒体服务器配置
|
||||
*/
|
||||
List<MediaServer> selectMediaServer();
|
||||
MediaServer selectMediaServerBytenantId(Long tenantId);
|
||||
MediaServer selectMediaServerBydeviceSipId(String deviceSipId);
|
||||
|
||||
/**
|
||||
* 查询流媒体服务器配置列表
|
||||
*
|
||||
* @param mediaServer 流媒体服务器配置
|
||||
* @return 流媒体服务器配置集合
|
||||
*/
|
||||
List<MediaServer> selectMediaServerList(MediaServer mediaServer);
|
||||
|
||||
/**
|
||||
* 新增流媒体服务器配置
|
||||
*
|
||||
* @param mediaServer 流媒体服务器配置
|
||||
* @return 结果
|
||||
*/
|
||||
int insertMediaServer(MediaServer mediaServer);
|
||||
|
||||
/**
|
||||
* 修改流媒体服务器配置
|
||||
*
|
||||
* @param mediaServer 流媒体服务器配置
|
||||
* @return 结果
|
||||
*/
|
||||
int updateMediaServer(MediaServer mediaServer);
|
||||
boolean syncMediaServer(MediaServer mediaServer,String secret);
|
||||
/**
|
||||
* 批量删除流媒体服务器配置
|
||||
*
|
||||
* @param ids 需要删除的流媒体服务器配置主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteMediaServerByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 删除流媒体服务器配置信息
|
||||
*
|
||||
* @param id 流媒体服务器配置主键
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteMediaServerById(Long id);
|
||||
|
||||
JSONObject getMediaList(String schema, String stream);
|
||||
JSONObject listRtpServer();
|
||||
VideoSessionInfo createRTPServer(SipConfig sipConfig, MediaServer mediaInfo, SipDevice device, VideoSessionInfo videoSessionInfo);
|
||||
MediaServer checkMediaServer(String ip, Long port, String secret);
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.fastbee.sip.service;
|
||||
|
||||
import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem;
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.domain.SipDeviceChannel;
|
||||
import com.fastbee.sip.model.RecordList;
|
||||
import com.fastbee.sip.server.msg.Alarm;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IMqttService {
|
||||
void publishInfo(SipDevice device);
|
||||
void publishStatus(SipDevice device, int deviceStatus);
|
||||
void publishEvent(Alarm alarm);
|
||||
void publishProperty(Long productId, String deviceNum, List<ThingsModelSimpleItem> thingsList, int delay);
|
||||
void publishChannelsProperty(String DeviceSipId, List<SipDeviceChannel> channels);
|
||||
void publishRecordsProperty(String DeviceSipId, RecordList recordList);
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.fastbee.sip.service;
|
||||
|
||||
import com.fastbee.sip.model.Stream;
|
||||
|
||||
public interface IPlayService {
|
||||
|
||||
Stream play(String deviceId, String channelId, boolean record);
|
||||
|
||||
Stream playback(String deviceId, String channelId, String startTime, String endTime);
|
||||
|
||||
String closeStream(String deviceId, String channelId, String streamId);
|
||||
|
||||
String playbackPause(String deviceId, String channelId, String streamId);
|
||||
|
||||
String playbackReplay(String deviceId, String channelId, String streamId);
|
||||
|
||||
String playbackSeek(String deviceId, String channelId, String streamId, long seektime);
|
||||
|
||||
String playbackSpeed(String deviceId, String channelId, String streamId, Integer speed);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.fastbee.sip.service;
|
||||
|
||||
import com.fastbee.sip.enums.Direct;
|
||||
|
||||
public interface IPtzCmdService {
|
||||
public boolean directPtzCmd(String deviceId, String channelId, Direct direct, Integer speed);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.fastbee.sip.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fastbee.sip.model.RecordItem;
|
||||
import com.fastbee.sip.model.RecordList;
|
||||
import com.fastbee.sip.model.Stream;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IRecordService {
|
||||
RecordList listDevRecord(String deviceId, String channelId, String startTime, String endTime);
|
||||
List<RecordItem> listRecord(String channelId, String sn);
|
||||
|
||||
JSONObject listServerRecord(String recordApi, Integer pageNum, Integer pageSize);
|
||||
JSONArray listServerRecordByDate(String recordApi, Integer year, Integer month, String app, String stream);
|
||||
JSONObject listServerRecordByStream(String recordApi, Integer pageNum, Integer pageSize, String app);
|
||||
JSONObject listServerRecordByApp(String recordApi, Integer pageNum, Integer pageSize);
|
||||
JSONObject listServerRecordByFile(String recordApi, Integer pageNum, Integer pageSize, String app, String stream, String startTime, String endTime);
|
||||
JSONObject listServerRecordByDevice(Integer pageNum, Integer pageSize, String deviceId, String channelId, String startTime, String endTime);
|
||||
boolean startRecord(String stream);
|
||||
boolean stopRecord(String stream);
|
||||
boolean isRecording(String stream);
|
||||
JSONObject getMp4RecordFile(String stream,String period);
|
||||
Stream download(String deviceId, String channelId,
|
||||
String startTime, String endTime, int downloadSpeed);
|
||||
JSONObject upload(String recordApi, String file);
|
||||
Stream playRecord(String deviceId, String channelId);
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.fastbee.sip.service;
|
||||
|
||||
import com.fastbee.sip.model.RecordList;
|
||||
import com.fastbee.sip.model.ZlmMediaServer;
|
||||
|
||||
public interface ISipCacheService {
|
||||
Long getCSEQ(String serverSipId);
|
||||
|
||||
void updateMediaInfo(ZlmMediaServer mediaServerConfig);
|
||||
|
||||
void setRecordList(String key, RecordList recordList);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user