mirror of
https://github.com/kerwincui/FastBee.git
synced 2025-10-18 14:10:57 +08:00
开源版本,视频直播功能
This commit is contained in:
@@ -176,6 +176,7 @@ public interface FastBeeConstant {
|
|||||||
String RECORDINFO_KEY = "sip:recordinfo:";
|
String RECORDINFO_KEY = "sip:recordinfo:";
|
||||||
String DEVICEID_KEY = "sip:deviceid:";
|
String DEVICEID_KEY = "sip:deviceid:";
|
||||||
String STREAM_KEY = "sip:stream:";
|
String STREAM_KEY = "sip:stream:";
|
||||||
|
String INVITE_KEY = "sip:invite:";
|
||||||
String SIP_CSEQ_PREFIX = "sip:CSEQ:";
|
String SIP_CSEQ_PREFIX = "sip:CSEQ:";
|
||||||
String DEFAULT_SIP_CONFIG = "sip:config";
|
String DEFAULT_SIP_CONFIG = "sip:config";
|
||||||
String DEFAULT_MEDIA_CONFIG = "sip:mediaconfig";
|
String DEFAULT_MEDIA_CONFIG = "sip:mediaconfig";
|
||||||
|
@@ -66,6 +66,14 @@ public class RedisKeyBuilder {
|
|||||||
return FastBeeConstant.REDIS.STREAM_KEY + steamId;
|
return FastBeeConstant.REDIS.STREAM_KEY + steamId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String buildStreamCacheKey(String deviceId, String channelId, String stream, String ssrc){
|
||||||
|
return FastBeeConstant.REDIS.STREAM_KEY + deviceId + ":" + channelId + ":" + stream + ":" + ssrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String buildInviteCacheKey(String type, String deviceId, String channelId, String stream, String ssrc){
|
||||||
|
return FastBeeConstant.REDIS.INVITE_KEY + type + ":"+ deviceId + ":" + channelId + ":" + stream + ":" + ssrc;
|
||||||
|
}
|
||||||
|
|
||||||
/**ipCSEQ缓存key*/
|
/**ipCSEQ缓存key*/
|
||||||
public static String buildSipCSEQCacheKey(String CSEQ){
|
public static String buildSipCSEQCacheKey(String CSEQ){
|
||||||
return FastBeeConstant.REDIS.SIP_CSEQ_PREFIX + CSEQ;
|
return FastBeeConstant.REDIS.SIP_CSEQ_PREFIX + CSEQ;
|
||||||
|
@@ -17,8 +17,12 @@
|
|||||||
<groupId>com.fastbee</groupId>
|
<groupId>com.fastbee</groupId>
|
||||||
<artifactId>mqtt-broker</artifactId>
|
<artifactId>mqtt-broker</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fastbee</groupId>
|
||||||
|
<artifactId>sip-server</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -0,0 +1,149 @@
|
|||||||
|
package com.fastbee.data.controller.media;
|
||||||
|
|
||||||
|
import com.fastbee.common.annotation.Log;
|
||||||
|
import com.fastbee.common.core.controller.BaseController;
|
||||||
|
import com.fastbee.common.core.domain.AjaxResult;
|
||||||
|
import com.fastbee.common.core.page.TableDataInfo;
|
||||||
|
import com.fastbee.common.enums.BusinessType;
|
||||||
|
import com.fastbee.common.utils.poi.ExcelUtil;
|
||||||
|
import com.fastbee.sip.domain.MediaServer;
|
||||||
|
import com.fastbee.sip.service.IMediaServerService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流媒体服务器配置Controller
|
||||||
|
*
|
||||||
|
* @author zhuangpeng.li
|
||||||
|
* @date 2022-11-30
|
||||||
|
*/
|
||||||
|
@Api(tags = "流媒体服务器配置")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/sip/mediaserver")
|
||||||
|
public class MediaServerController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private IMediaServerService mediaServerService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询流媒体服务器配置列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询流媒体服务器配置列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(MediaServer mediaServer)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<MediaServer> list = mediaServerService.selectMediaServerList(mediaServer);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出流媒体服务器配置列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("导出流媒体服务器配置列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@Log(title = "流媒体服务器配置", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, MediaServer mediaServer)
|
||||||
|
{
|
||||||
|
List<MediaServer> list = mediaServerService.selectMediaServerList(mediaServer);
|
||||||
|
ExcelUtil<MediaServer> util = new ExcelUtil<MediaServer>(MediaServer.class);
|
||||||
|
util.exportExcel(response, list, "流媒体服务器配置数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流媒体服务器配置详细信息,只获取第一条
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "获取流媒体服务器配置详细信息", notes = "只获取第一条")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:query')")
|
||||||
|
@GetMapping()
|
||||||
|
public AjaxResult getInfo()
|
||||||
|
{
|
||||||
|
List<MediaServer> list=mediaServerService.selectMediaServer();
|
||||||
|
if(list==null || list.size()==0){
|
||||||
|
MediaServer mediaServer=new MediaServer();
|
||||||
|
// 设置默认值
|
||||||
|
mediaServer.setEnabled(1);
|
||||||
|
mediaServer.setDomain("");
|
||||||
|
mediaServer.setIp("");
|
||||||
|
mediaServer.setPortHttp(8082L);
|
||||||
|
mediaServer.setPortHttps(8443L);
|
||||||
|
mediaServer.setPortRtmp(1935L);
|
||||||
|
mediaServer.setPortRtsp(554L);
|
||||||
|
mediaServer.setProtocol("HTTP");
|
||||||
|
mediaServer.setSecret("035c73f7-bb6b-4889-a715-d9eb2d192xxx");
|
||||||
|
mediaServer.setRtpPortRange("30000,30500");
|
||||||
|
list=new ArrayList<>();
|
||||||
|
list.add(mediaServer);
|
||||||
|
}
|
||||||
|
return AjaxResult.success(list.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增流媒体服务器配置
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增流媒体服务器配置")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:add')")
|
||||||
|
@Log(title = "流媒体服务器配置", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody MediaServer mediaServer)
|
||||||
|
{
|
||||||
|
return toAjax(mediaServerService.insertMediaServer(mediaServer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改流媒体服务器配置
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改流媒体服务器配置")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:edit')")
|
||||||
|
@Log(title = "流媒体服务器配置", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody MediaServer mediaServer)
|
||||||
|
{
|
||||||
|
return toAjax(mediaServerService.updateMediaServer(mediaServer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除流媒体服务器配置
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除流媒体服务器配置")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:remove')")
|
||||||
|
@Log(title = "流媒体服务器配置", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(mediaServerService.deleteMediaServerByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取流媒体服务器视频流信息列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping("/mediaList/{schema}/{stream}")
|
||||||
|
public AjaxResult getMediaList(@PathVariable String schema,
|
||||||
|
@PathVariable String stream)
|
||||||
|
{
|
||||||
|
return AjaxResult.success("success!", mediaServerService.getMediaList(schema,stream));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取rtp推流端口列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping("/listRtpServer")
|
||||||
|
public AjaxResult listRtpServer()
|
||||||
|
{
|
||||||
|
return AjaxResult.success("success!", mediaServerService.listRtpServer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("检验流媒体服务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping(value = "/check")
|
||||||
|
public AjaxResult checkMediaServer(@RequestParam String ip, @RequestParam Long port, @RequestParam String secret) {
|
||||||
|
return AjaxResult.success("success!", mediaServerService.checkMediaServer(ip, port, secret));
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,62 @@
|
|||||||
|
package com.fastbee.data.controller.media;
|
||||||
|
|
||||||
|
import com.fastbee.common.core.controller.BaseController;
|
||||||
|
import com.fastbee.common.core.domain.AjaxResult;
|
||||||
|
import com.fastbee.sip.service.IPlayService;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/sip/player")
|
||||||
|
public class PlayerController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IPlayService playService;
|
||||||
|
|
||||||
|
@GetMapping("/getBigScreenUrl/{deviceId}/{channelId}")
|
||||||
|
public AjaxResult getBigScreenUrl(@PathVariable String deviceId, @PathVariable String channelId) {
|
||||||
|
return AjaxResult.success("success!", playService.play(deviceId, channelId,false).getHttps_fmp4());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("直播播放")
|
||||||
|
@GetMapping("/play/{deviceId}/{channelId}")
|
||||||
|
public AjaxResult play(@PathVariable String deviceId, @PathVariable String channelId) {
|
||||||
|
return AjaxResult.success("success!", playService.play(deviceId, channelId,false));
|
||||||
|
}
|
||||||
|
@ApiOperation("回放播放")
|
||||||
|
@GetMapping("/playback/{deviceId}/{channelId}")
|
||||||
|
public AjaxResult playback(@PathVariable String deviceId,
|
||||||
|
@PathVariable String channelId, String start, String end) {
|
||||||
|
return AjaxResult.success("success!", playService.playback(deviceId, channelId, start, end));
|
||||||
|
}
|
||||||
|
@ApiOperation("停止推流")
|
||||||
|
@GetMapping("/closeStream/{deviceId}/{channelId}/{streamId}")
|
||||||
|
public AjaxResult closeStream(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String streamId) {
|
||||||
|
return AjaxResult.success("success!", playService.closeStream(deviceId, channelId, streamId));
|
||||||
|
}
|
||||||
|
@ApiOperation("回放暂停")
|
||||||
|
@GetMapping("/playbackPause/{deviceId}/{channelId}/{streamId}")
|
||||||
|
public AjaxResult playbackPause(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String streamId) {
|
||||||
|
return AjaxResult.success("success!", playService.playbackPause(deviceId, channelId, streamId));
|
||||||
|
}
|
||||||
|
@ApiOperation("回放恢复")
|
||||||
|
@GetMapping("/playbackReplay/{deviceId}/{channelId}/{streamId}")
|
||||||
|
public AjaxResult playbackReplay(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String streamId) {
|
||||||
|
return AjaxResult.success("success!", playService.playbackReplay(deviceId, channelId, streamId));
|
||||||
|
}
|
||||||
|
@ApiOperation("录像回放定位")
|
||||||
|
@GetMapping("/playbackSeek/{deviceId}/{channelId}/{streamId}")
|
||||||
|
public AjaxResult playbackSeek(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String streamId, long seek) {
|
||||||
|
return AjaxResult.success("success!", playService.playbackSeek(deviceId, channelId, streamId, seek));
|
||||||
|
}
|
||||||
|
@ApiOperation("录像倍速播放")
|
||||||
|
@GetMapping("/playbackSpeed/{deviceId}/{channelId}/{streamId}")
|
||||||
|
public AjaxResult playbackSpeed(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String streamId, Integer speed) {
|
||||||
|
return AjaxResult.success("success!", playService.playbackSpeed(deviceId, channelId, streamId, speed));
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,73 @@
|
|||||||
|
package com.fastbee.data.controller.media;
|
||||||
|
|
||||||
|
import com.fastbee.common.core.domain.AjaxResult;
|
||||||
|
import com.fastbee.sip.enums.Direct;
|
||||||
|
import com.fastbee.sip.model.PtzDirectionInput;
|
||||||
|
import com.fastbee.sip.model.PtzscaleInput;
|
||||||
|
import com.fastbee.sip.service.IPtzCmdService;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/sip/ptz")
|
||||||
|
public class PtzController {
|
||||||
|
@Autowired
|
||||||
|
private IPtzCmdService ptzCmdService;
|
||||||
|
@ApiOperation("云台方向控制")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@PostMapping("/direction/{deviceId}/{channelId}")
|
||||||
|
public AjaxResult direction(@PathVariable String deviceId, @PathVariable String channelId, @RequestBody PtzDirectionInput ptzDirectionInput) {
|
||||||
|
Direct direct = null;
|
||||||
|
int leftRight = ptzDirectionInput.getLeftRight();
|
||||||
|
int upDown = ptzDirectionInput.getUpDown();
|
||||||
|
if (leftRight == 1) {
|
||||||
|
direct = Direct.RIGHT;
|
||||||
|
} else if (leftRight == 2) {
|
||||||
|
direct = Direct.LEFT;
|
||||||
|
} else if (upDown == 1) {
|
||||||
|
direct = Direct.UP;
|
||||||
|
} else if (upDown == 2) {
|
||||||
|
direct = Direct.DOWN;
|
||||||
|
} else {
|
||||||
|
direct = Direct.STOP;
|
||||||
|
}
|
||||||
|
Integer speed = ptzDirectionInput.getMoveSpeed();
|
||||||
|
return AjaxResult.success("success!", ptzCmdService.directPtzCmd(deviceId, channelId, direct, speed));
|
||||||
|
}
|
||||||
|
@ApiOperation("云台缩放控制")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@PostMapping("/scale/{deviceId}/{channelId}")
|
||||||
|
public AjaxResult scale(@PathVariable String deviceId, @PathVariable String channelId, @RequestBody PtzscaleInput ptzscaleInput) {
|
||||||
|
Direct direct = null;
|
||||||
|
if (ptzscaleInput.getInOut() == 1) {
|
||||||
|
direct = Direct.ZOOM_IN;
|
||||||
|
} else if (ptzscaleInput.getInOut() == 2) {
|
||||||
|
direct = Direct.ZOOM_OUT;
|
||||||
|
} else {
|
||||||
|
direct = Direct.STOP;
|
||||||
|
}
|
||||||
|
Integer speed = ptzscaleInput.getScaleSpeed();
|
||||||
|
return AjaxResult.success("success!", ptzCmdService.directPtzCmd(deviceId, channelId, direct, speed));
|
||||||
|
}
|
||||||
|
@ApiOperation("云台ptz控制")
|
||||||
|
@PostMapping("/ptz/{deviceId}/{channelId}/{direct}/{speed}")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
public AjaxResult ptzControl(@PathVariable String deviceId,
|
||||||
|
@PathVariable String channelId,
|
||||||
|
@PathVariable Direct direct,
|
||||||
|
@PathVariable Integer speed) {
|
||||||
|
return AjaxResult.success("success!", ptzCmdService.directPtzCmd(deviceId, channelId, direct, speed));
|
||||||
|
}
|
||||||
|
@ApiOperation("云台停止控制")
|
||||||
|
@PostMapping("/ptz/{deviceId}/{channelId}/STOP")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
public AjaxResult ptzControlStop(@PathVariable String deviceId,
|
||||||
|
@PathVariable String channelId) {
|
||||||
|
return AjaxResult.success("success!", ptzCmdService.directPtzCmd(deviceId, channelId, Direct.STOP, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,155 @@
|
|||||||
|
package com.fastbee.data.controller.media;
|
||||||
|
|
||||||
|
import com.fastbee.common.core.controller.BaseController;
|
||||||
|
import com.fastbee.common.core.domain.AjaxResult;
|
||||||
|
import com.fastbee.sip.model.RecordList;
|
||||||
|
import com.fastbee.sip.service.IRecordService;
|
||||||
|
import com.fastbee.sip.util.WebAsyncUtil;
|
||||||
|
import com.fastbee.sip.util.result.BaseResult;
|
||||||
|
import com.fastbee.sip.util.result.CodeEnum;
|
||||||
|
import com.fastbee.sip.util.result.DataResult;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.context.request.async.WebAsyncTask;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/sip/record")
|
||||||
|
public class RecordController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IRecordService recordService;
|
||||||
|
|
||||||
|
@Qualifier("taskExecutor")
|
||||||
|
@Autowired
|
||||||
|
private ThreadPoolTaskExecutor taskExecutor;
|
||||||
|
@ApiOperation("设备录像查询")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping("/devquery/{deviceId}/{channelId}")
|
||||||
|
public WebAsyncTask<Object> devquery(@PathVariable String deviceId,
|
||||||
|
@PathVariable String channelId, String start, String end) {
|
||||||
|
return WebAsyncUtil.init(taskExecutor, () -> {
|
||||||
|
try {
|
||||||
|
RecordList result = recordService.listDevRecord(deviceId, channelId, start, end);
|
||||||
|
return DataResult.out(CodeEnum.SUCCESS, result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("", e);
|
||||||
|
return BaseResult.out(CodeEnum.FAIL, e.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ApiOperation("设备录像缓存查询")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping("/query/{channelId}/{sn}")
|
||||||
|
public AjaxResult list(@PathVariable String channelId,
|
||||||
|
@PathVariable String sn) {
|
||||||
|
return AjaxResult.success("success!", recordService.listRecord(channelId, sn));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("指定流ID开始录像")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping("/start/{stream}")
|
||||||
|
public AjaxResult startRecord(@PathVariable String stream) {
|
||||||
|
boolean result = recordService.startRecord(stream);
|
||||||
|
if (result) {
|
||||||
|
return AjaxResult.success("success!");
|
||||||
|
} else {
|
||||||
|
return AjaxResult.error("error!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("指定流ID停止录像")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping("/stop/{stream}")
|
||||||
|
public AjaxResult stopRecord(@PathVariable String stream) {
|
||||||
|
boolean result = recordService.stopRecord(stream);
|
||||||
|
if (result) {
|
||||||
|
return AjaxResult.success("success!");
|
||||||
|
} else {
|
||||||
|
return AjaxResult.error("error!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取流对应的录像文件列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping("/file/{stream}/{period}")
|
||||||
|
public AjaxResult getMp4RecordFile(@PathVariable String stream,
|
||||||
|
@PathVariable String period) {
|
||||||
|
return AjaxResult.success("success!", recordService.getMp4RecordFile(stream, period));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("直播录像")
|
||||||
|
@GetMapping("/play/{deviceId}/{channelId}")
|
||||||
|
public AjaxResult playRecord(@PathVariable String deviceId, @PathVariable String channelId) {
|
||||||
|
logger.debug(String.format("直播录像 API调用,deviceId:%s,channelId:%s", deviceId, channelId));
|
||||||
|
return AjaxResult.success("success!", recordService.playRecord(deviceId, channelId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:sip:record:download')")
|
||||||
|
@ApiOperation("设备录像下载")
|
||||||
|
@GetMapping("/download/{deviceId}/{channelId}")
|
||||||
|
public AjaxResult download(@PathVariable String deviceId, @PathVariable String channelId,
|
||||||
|
String startTime, String endTime, String speed) {
|
||||||
|
logger.debug(String.format("设备录像下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, speed));
|
||||||
|
return AjaxResult.success("success!", recordService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(speed)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOperation("查询服务端录像列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
|
||||||
|
@GetMapping("/serverRecord/list")
|
||||||
|
public AjaxResult listServerRecord(@RequestParam Integer pageNum,
|
||||||
|
@RequestParam Integer pageSize, @RequestParam String recordApi) {
|
||||||
|
try{
|
||||||
|
Object data = recordService.listServerRecord(recordApi, pageNum, pageSize);
|
||||||
|
return AjaxResult.success("success!", data);
|
||||||
|
}catch(Exception e){
|
||||||
|
return AjaxResult.error("连接超时或发生错误,未获取到数据!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ApiOperation("通过日期查询服务端录像列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
|
||||||
|
@GetMapping("/serverRecord/date/list")
|
||||||
|
public AjaxResult listServerRecordByDate(@RequestParam(required = false) Integer year,
|
||||||
|
@RequestParam(required = false) Integer month, @RequestParam String app, @RequestParam String stream, @RequestParam String recordApi) {
|
||||||
|
return AjaxResult.success("success!", recordService.listServerRecordByDate(recordApi, year, month, app, stream));
|
||||||
|
}
|
||||||
|
@ApiOperation("通过流ID查询服务端录像列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
|
||||||
|
@GetMapping("/serverRecord/stream/list")
|
||||||
|
public AjaxResult listServerRecordByStream(@RequestParam Integer pageNum,
|
||||||
|
@RequestParam Integer pageSize, @RequestParam String app, @RequestParam String recordApi) {
|
||||||
|
return AjaxResult.success("success!", recordService.listServerRecordByStream(recordApi, pageNum, pageSize, app));
|
||||||
|
}
|
||||||
|
@ApiOperation("通过应用名查询服务端录像列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
|
||||||
|
@GetMapping("/serverRecord/app/list")
|
||||||
|
public AjaxResult listServerRecordByApp(@RequestParam Integer pageNum,
|
||||||
|
@RequestParam Integer pageSize, @RequestParam String recordApi) {
|
||||||
|
return AjaxResult.success("success!", recordService.listServerRecordByApp(recordApi, pageNum, pageSize));
|
||||||
|
}
|
||||||
|
@ApiOperation("通过文件名查询服务端录像列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
|
||||||
|
@GetMapping("/serverRecord/file/list")
|
||||||
|
public AjaxResult listServerRecordByFile(@RequestParam Integer pageNum, @RequestParam Integer pageSize,
|
||||||
|
@RequestParam String app, @RequestParam String stream,
|
||||||
|
@RequestParam String startTime, @RequestParam String endTime, @RequestParam String recordApi) {
|
||||||
|
return AjaxResult.success("success!", recordService.listServerRecordByFile(recordApi, pageNum, pageSize, app, stream, startTime, endTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("通过设备信息查询服务端录像列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
|
||||||
|
@GetMapping("/serverRecord/device/list")
|
||||||
|
public AjaxResult getServerRecordByDevice(@RequestParam Integer pageNum, @RequestParam Integer pageSize,
|
||||||
|
@RequestParam String deviceId, @RequestParam String channelId,
|
||||||
|
@RequestParam String startTime, @RequestParam String endTime) {
|
||||||
|
return AjaxResult.success("success!", recordService.listServerRecordByDevice(pageNum, pageSize, deviceId, channelId, startTime, endTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,81 @@
|
|||||||
|
package com.fastbee.data.controller.media;
|
||||||
|
|
||||||
|
import com.fastbee.common.annotation.Log;
|
||||||
|
import com.fastbee.common.core.controller.BaseController;
|
||||||
|
import com.fastbee.common.core.domain.AjaxResult;
|
||||||
|
import com.fastbee.common.enums.BusinessType;
|
||||||
|
import com.fastbee.sip.domain.SipConfig;
|
||||||
|
import com.fastbee.sip.service.ISipConfigService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sip系统配置Controller
|
||||||
|
*
|
||||||
|
* @author zhuangpeng.li
|
||||||
|
* @date 2022-11-30
|
||||||
|
*/
|
||||||
|
@Api(tags = "sip系统配置")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/sip/sipconfig")
|
||||||
|
public class SipConfigController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private ISipConfigService sipConfigService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取产品下第一条sip系统配置详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取产品下sip系统配置信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:query')")
|
||||||
|
@GetMapping(value = "/{productId}/{isDefault}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("productId") Long productId, @PathVariable("isDefault") Boolean isDefault) {
|
||||||
|
SipConfig sipConfig = isDefault ? sipConfigService.GetDefaultSipConfig() : sipConfigService.selectSipConfigByProductId(productId);
|
||||||
|
return AjaxResult.success(sipConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增sip系统配置
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增sip系统配置")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:add')")
|
||||||
|
@Log(title = "sip系统配置", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody SipConfig sipConfig) {
|
||||||
|
return AjaxResult.success(sipConfigService.insertSipConfig(sipConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改sip系统配置
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改sip系统配置")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:edit')")
|
||||||
|
@Log(title = "sip系统配置", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody SipConfig sipConfig) {
|
||||||
|
return toAjax(sipConfigService.updateSipConfig(sipConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除sip系统配置
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除sip系统配置")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:remove')")
|
||||||
|
@Log(title = "sip系统配置", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||||
|
return toAjax(sipConfigService.deleteSipConfigByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("批量删除sip系统配置")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:remove')")
|
||||||
|
@Log(title = "sip系统配置", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/product/{productIds}")
|
||||||
|
public AjaxResult removeByProductId(@PathVariable Long[] productIds) {
|
||||||
|
// 设备可能不存在通道,可以返回0
|
||||||
|
int result = sipConfigService.deleteSipConfigByProductIds(productIds);
|
||||||
|
return AjaxResult.success(result);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,106 @@
|
|||||||
|
package com.fastbee.data.controller.media;
|
||||||
|
|
||||||
|
import com.fastbee.common.annotation.Log;
|
||||||
|
import com.fastbee.common.core.controller.BaseController;
|
||||||
|
import com.fastbee.common.core.domain.AjaxResult;
|
||||||
|
import com.fastbee.common.core.page.TableDataInfo;
|
||||||
|
import com.fastbee.common.enums.BusinessType;
|
||||||
|
import com.fastbee.common.utils.poi.ExcelUtil;
|
||||||
|
import com.fastbee.sip.domain.SipDeviceChannel;
|
||||||
|
import com.fastbee.sip.service.ISipDeviceChannelService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监控设备通道信息Controller
|
||||||
|
*
|
||||||
|
* @author zhuangpeng.li
|
||||||
|
* @date 2022-10-07
|
||||||
|
*/
|
||||||
|
@Api(tags = "监控设备通道信息")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/sip/channel")
|
||||||
|
public class SipDeviceChannelController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private ISipDeviceChannelService sipDeviceChannelService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询监控设备通道信息列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询监控设备通道信息列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(SipDeviceChannel sipDeviceChannel)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<SipDeviceChannel> list = sipDeviceChannelService.selectSipDeviceChannelList(sipDeviceChannel);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出监控设备通道信息列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("导出监控设备通道信息列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@Log(title = "监控设备通道信息", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, SipDeviceChannel sipDeviceChannel)
|
||||||
|
{
|
||||||
|
List<SipDeviceChannel> list = sipDeviceChannelService.selectSipDeviceChannelList(sipDeviceChannel);
|
||||||
|
ExcelUtil<SipDeviceChannel> util = new ExcelUtil<SipDeviceChannel>(SipDeviceChannel.class);
|
||||||
|
util.exportExcel(response, list, "监控设备通道信息数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取监控设备通道信息详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取监控设备通道信息详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:query')")
|
||||||
|
@GetMapping(value = "/{channelId}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("channelId") Long channelId)
|
||||||
|
{
|
||||||
|
return AjaxResult.success(sipDeviceChannelService.selectSipDeviceChannelByChannelId(channelId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增监控设备通道信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增监控设备通道信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:add')")
|
||||||
|
@Log(title = "监控设备通道信息", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping(value = "/{createNum}")
|
||||||
|
public AjaxResult add(@PathVariable("createNum") Long createNum, @RequestBody SipDeviceChannel sipDeviceChannel) {
|
||||||
|
return AjaxResult.success("操作成功", sipDeviceChannelService.insertSipDeviceChannelGen(createNum, sipDeviceChannel));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改监控设备通道信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改监控设备通道信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:edit')")
|
||||||
|
@Log(title = "监控设备通道信息", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody SipDeviceChannel sipDeviceChannel)
|
||||||
|
{
|
||||||
|
return toAjax(sipDeviceChannelService.updateSipDeviceChannel(sipDeviceChannel));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除监控设备通道信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除监控设备通道信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:remove')")
|
||||||
|
@Log(title = "监控设备通道信息", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{channelIds}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] channelIds)
|
||||||
|
{
|
||||||
|
return toAjax(sipDeviceChannelService.deleteSipDeviceChannelByChannelIds(channelIds));
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,144 @@
|
|||||||
|
package com.fastbee.data.controller.media;
|
||||||
|
|
||||||
|
import com.fastbee.common.annotation.Log;
|
||||||
|
import com.fastbee.common.core.controller.BaseController;
|
||||||
|
import com.fastbee.common.core.domain.AjaxResult;
|
||||||
|
import com.fastbee.common.core.page.TableDataInfo;
|
||||||
|
import com.fastbee.common.enums.BusinessType;
|
||||||
|
import com.fastbee.common.utils.file.FileUploadUtils;
|
||||||
|
import com.fastbee.common.utils.poi.ExcelUtil;
|
||||||
|
import com.fastbee.sip.domain.SipDevice;
|
||||||
|
import com.fastbee.sip.service.ISipDeviceService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.apache.commons.compress.utils.IOUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监控设备Controller
|
||||||
|
*
|
||||||
|
* @author zhuangpeng.li
|
||||||
|
* @date 2022-10-07
|
||||||
|
*/
|
||||||
|
@Api(tags = "监控设备")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/sip/device")
|
||||||
|
public class SipDeviceController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private ISipDeviceService sipDeviceService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询监控设备列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询监控设备列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(SipDevice sipDevice)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<SipDevice> list = sipDeviceService.selectSipDeviceList(sipDevice);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("查询监控设备树结构")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@GetMapping("/listchannel/{deviceId}")
|
||||||
|
public AjaxResult listchannel(@PathVariable("deviceId") String deviceId)
|
||||||
|
{
|
||||||
|
return AjaxResult.success(sipDeviceService.selectSipDeviceChannelList(deviceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出监控设备列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("导出监控设备列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:list')")
|
||||||
|
@Log(title = "监控设备", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HttpServletResponse response, SipDevice sipDevice)
|
||||||
|
{
|
||||||
|
List<SipDevice> list = sipDeviceService.selectSipDeviceList(sipDevice);
|
||||||
|
ExcelUtil<SipDevice> util = new ExcelUtil<SipDevice>(SipDevice.class);
|
||||||
|
util.exportExcel(response, list, "监控设备数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取监控设备详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取监控设备详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:query')")
|
||||||
|
@GetMapping(value = "/{deviceId}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("deviceId") String deviceId)
|
||||||
|
{
|
||||||
|
return AjaxResult.success(sipDeviceService.selectSipDeviceBySipId(deviceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增监控设备
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增监控设备")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:add')")
|
||||||
|
@Log(title = "监控设备", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody SipDevice sipDevice)
|
||||||
|
{
|
||||||
|
return toAjax(sipDeviceService.insertSipDevice(sipDevice));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改监控设备
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改监控设备")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:edit')")
|
||||||
|
@Log(title = "监控设备", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody SipDevice sipDevice)
|
||||||
|
{
|
||||||
|
return toAjax(sipDeviceService.updateSipDevice(sipDevice));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除监控设备
|
||||||
|
*/
|
||||||
|
@ApiOperation("根据设备id批量删除监控设备")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:remove')")
|
||||||
|
@Log(title = "监控设备", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{deviceIds}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] deviceIds)
|
||||||
|
{
|
||||||
|
return toAjax(sipDeviceService.deleteSipDeviceByDeviceIds(deviceIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("根据sipId删除")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:remove')")
|
||||||
|
@Log(title = "监控设备", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/sipid/{sipId}")
|
||||||
|
public AjaxResult remove(@PathVariable String sipId)
|
||||||
|
{
|
||||||
|
return toAjax(sipDeviceService.deleteSipDeviceBySipId(sipId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("根据设备id捕捉")
|
||||||
|
@PreAuthorize("@ss.hasPermi('iot:video:query')")
|
||||||
|
@GetMapping("/snap/{deviceId}/{channelId}")
|
||||||
|
public void getSnap(HttpServletResponse resp, @PathVariable String deviceId, @PathVariable String channelId) {
|
||||||
|
try {
|
||||||
|
final InputStream in = Files.newInputStream(new File(FileUploadUtils.getDefaultBaseDir() + File.separator + "snap" + File.separator + deviceId + "_" + channelId + ".jpg").toPath());
|
||||||
|
resp.setContentType(MediaType.IMAGE_PNG_VALUE);
|
||||||
|
IOUtils.copy(in, resp.getOutputStream());
|
||||||
|
} catch (IOException e) {
|
||||||
|
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,105 @@
|
|||||||
|
package com.fastbee.data.controller.media;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.fastbee.sip.service.IZmlHookService;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/zlmhook")
|
||||||
|
public class ZmlHookController
|
||||||
|
{
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IZmlHookService zmlHookService;
|
||||||
|
@ApiOperation("访问流媒体服务器上的文件时触发回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_http_access", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onHttpAccess(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onHttpAccess(json).toString(), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
@ApiOperation("播放器鉴权事件回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onPlay(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onPlay(json).toString(), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
@ApiOperation("rtsp/rtmp/rtp推流鉴权事件回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onPublish(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onPublish(json).toString(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
@ApiOperation("流无人观看时事件回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onStreamNoneReader(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onStreamNoneReader(json).toString(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
@ApiOperation("流未找到事件回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onStreamNotFound(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onStreamNotFound(json).toString(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
@ApiOperation("流注册或注销时触发此事件回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onStreamChanged(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onStreamChanged(json).toString(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
@ApiOperation("流量统计事件回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_flow_report", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onFlowReport(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onFlowReport(json).toString(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
@ApiOperation("rtp服务器长时间未收到数据超时回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onRtpServerTimeout(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onRtpServerTimeout(json).toString(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("rtp发送停止回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onSendRtpStopped(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onSendRtpStopped(json).toString(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("录制mp4完成后通知事件回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_record_mp4", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onRecordMp4(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onRecordMp4(json).toString(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("流媒体服务器启动回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onServerStarted(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onServerStarted(json).toString(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("流媒体服务器心跳回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onServerKeepalive(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onServerKeepalive(json).toString(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("流媒体服务器存活回调")
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/on_server_exited", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<String> onServerExited(@RequestBody JSONObject json){
|
||||||
|
return new ResponseEntity<String>(zmlHookService.onServerExited(json).toString(),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
29
springboot/fastbee-server/sip-server/README.md
Normal file
29
springboot/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 获取流信息
|
||||||
|
|
74
springboot/fastbee-server/sip-server/pom.xml
Normal file
74
springboot/fastbee-server/sip-server/pom.xml
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?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.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fastbee</groupId>
|
||||||
|
<artifactId>fastbee-mq</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,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,270 @@
|
|||||||
|
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 org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -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),
|
||||||
|
online(2),
|
||||||
|
offline(3),
|
||||||
|
off(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,194 @@
|
|||||||
|
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.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;
|
||||||
|
|
||||||
|
@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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} 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,76 @@
|
|||||||
|
package com.fastbee.sip.mapper;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
@@ -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,41 @@
|
|||||||
|
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 fmp4;
|
||||||
|
private String https_fmp4;
|
||||||
|
private String ws_fmp4;
|
||||||
|
private String hls;
|
||||||
|
private String https_hls;
|
||||||
|
private String ws_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,106 @@
|
|||||||
|
package com.fastbee.sip.server;
|
||||||
|
|
||||||
|
import com.fastbee.sip.domain.SipDevice;
|
||||||
|
import com.fastbee.sip.server.msg.ConfigDownload;
|
||||||
|
import com.fastbee.sip.server.msg.DeviceControl;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.sip.ClientTransaction;
|
||||||
|
import javax.sip.PeerUnavailableException;
|
||||||
|
import javax.sip.RequestEvent;
|
||||||
|
import javax.sip.message.Request;
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订阅通道目录,发送订阅请求后
|
||||||
|
*
|
||||||
|
* @param device device
|
||||||
|
* @param from 订阅有效期从
|
||||||
|
* @param to 订阅有效期止
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void subscribeCatalog(SipDevice device, Date from, Date to) throws PeerUnavailableException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载设备配置信息,可指定配置类型,如果未指定类型则获取所有类型的配置
|
||||||
|
*
|
||||||
|
* @param device 设备信息
|
||||||
|
* @param configType 要下载的配置类型
|
||||||
|
* @return 配置信息
|
||||||
|
*/
|
||||||
|
ConfigDownload downloadConfig(SipDevice device, ConfigDownload.ConfigType... configType);
|
||||||
|
SipMessage messageToObj(RequestEvent event);
|
||||||
|
/**
|
||||||
|
* 发送SIP原始请求
|
||||||
|
*
|
||||||
|
* @param device 设备
|
||||||
|
* @param request 原始请求
|
||||||
|
* @param awaitAck 是否等待响应
|
||||||
|
* @return 事务信息
|
||||||
|
*/
|
||||||
|
ClientTransaction request(SipDevice device, Request request, boolean awaitAck);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发起一个请求,并等待响应,不同的请求方式以及内容,响应的内容不同。
|
||||||
|
*
|
||||||
|
* @param transaction ClientTransaction
|
||||||
|
* @param request Request
|
||||||
|
* @param awaitAck 是否等待响应
|
||||||
|
* @return 响应结果
|
||||||
|
*/
|
||||||
|
Object request(ClientTransaction transaction, Request request, boolean awaitAck);
|
||||||
|
|
||||||
|
<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,93 @@
|
|||||||
|
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 javax.sip.*;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
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);
|
||||||
|
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,317 @@
|
|||||||
|
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
|
||||||
|
@SneakyThrows
|
||||||
|
public void subscribeCatalog(SipDevice device, Date from, Date to) {
|
||||||
|
String fromTimeString = SipUtil.dateToISO8601(from);
|
||||||
|
String toTimeString = SipUtil.dateToISO8601(to);
|
||||||
|
;
|
||||||
|
int expires = (int) ((to.getTime() - from.getTime()) / 1000);
|
||||||
|
|
||||||
|
ExpiresHeader header = sipFactory.createHeaderFactory().createExpiresHeader(expires);
|
||||||
|
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" +
|
||||||
|
"<StartTime>" + fromTimeString + "</StartTime>\r\n" +
|
||||||
|
"<EndTime>" + toTimeString + "</EndTime>\r\n" +
|
||||||
|
"</Query>\r\n",
|
||||||
|
Request.SUBSCRIBE,
|
||||||
|
device,
|
||||||
|
"ViaSubscribeCatalog",
|
||||||
|
"SubscribeCatalogTag",
|
||||||
|
null,
|
||||||
|
header
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigDownload downloadConfig(SipDevice device, ConfigDownload.ConfigType... configType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientTransaction request(SipDevice device, Request request, boolean awaitAck) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object request(ClientTransaction transaction, Request request, boolean awaitAck) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user