Merge branch 'master' into dev/数据库统合
# Conflicts: # src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceChannelService.java # src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceChannelServiceImpl.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java # src/main/java/com/genersoft/iot/vmp/streamProxy/service/impl/StreamProxyPlayServiceImpl.java # web_src/src/components/DeviceList.vue
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
package com.genersoft.iot.vmp.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
|
||||
/**
|
||||
* 支持的通道数据类型
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 解析收到的前端控制指令
|
||||
*/
|
||||
@Data
|
||||
public class FrontEndCode {
|
||||
|
||||
|
||||
public static String encode(IFrontEndControlCode frontEndControlCode){
|
||||
return frontEndControlCode.encode();
|
||||
}
|
||||
|
||||
public static IFrontEndControlCode decode(@NotNull String cmdStr) {
|
||||
if (cmdStr.length() != 16) {
|
||||
return null;
|
||||
}
|
||||
String cmdCodeStr = cmdStr.substring(6, 8);
|
||||
int cmdCode = Integer.parseInt(cmdCodeStr, 16);
|
||||
if (cmdCode < 39) {
|
||||
// PTZ指令
|
||||
FrontEndControlCodeForPTZ codeForPTZ = new FrontEndControlCodeForPTZ();
|
||||
int zoomOut = cmdCode >> 5 & 1;
|
||||
if (zoomOut == 1) {
|
||||
codeForPTZ.setZoom(0);
|
||||
}
|
||||
int zoomIn = cmdCode >> 4 & 1;
|
||||
if (zoomIn == 1) {
|
||||
codeForPTZ.setZoom(1);
|
||||
}
|
||||
int tiltUp = cmdCode >> 3 & 1;
|
||||
if (tiltUp == 1) {
|
||||
codeForPTZ.setTilt(0);
|
||||
}
|
||||
int tiltDown = cmdCode >> 2 & 1;
|
||||
if (tiltDown == 1) {
|
||||
codeForPTZ.setTilt(1);
|
||||
}
|
||||
int panLeft = cmdCode >> 1 & 1;
|
||||
if (panLeft == 1) {
|
||||
codeForPTZ.setPan(0);
|
||||
}
|
||||
int panRight = cmdCode & 1;
|
||||
if (panRight == 1) {
|
||||
codeForPTZ.setPan(1);
|
||||
}
|
||||
String param1Str = cmdStr.substring(8, 10);
|
||||
codeForPTZ.setPanSpeed(Integer.parseInt(param1Str, 16));
|
||||
String param2Str = cmdStr.substring(10, 12);
|
||||
codeForPTZ.setTiltSpeed(Integer.parseInt(param2Str, 16));
|
||||
String param3Str = cmdStr.substring(12, 13);
|
||||
codeForPTZ.setZoomSpeed(Integer.parseInt(param3Str, 16));
|
||||
return codeForPTZ;
|
||||
}else if (cmdCode < 74) {
|
||||
// FI指令
|
||||
FrontEndControlCodeForFI codeForFI = new FrontEndControlCodeForFI();
|
||||
int irisOut = cmdCode >> 3 & 1;
|
||||
if (irisOut == 1) {
|
||||
codeForFI.setIris(0);
|
||||
}
|
||||
int irisIn = cmdCode >> 2 & 1;
|
||||
if (irisIn == 1) {
|
||||
codeForFI.setIris(1);
|
||||
}
|
||||
int focusNear = cmdCode >> 1 & 1;
|
||||
if (focusNear == 1) {
|
||||
codeForFI.setFocus(0);
|
||||
}
|
||||
int focusFar = cmdCode & 1;
|
||||
if (focusFar == 1) {
|
||||
codeForFI.setFocus(1);
|
||||
}
|
||||
|
||||
String param1Str = cmdStr.substring(8, 10);
|
||||
codeForFI.setFocusSpeed(Integer.parseInt(param1Str, 16));
|
||||
String param2Str = cmdStr.substring(10, 12);
|
||||
codeForFI.setIrisSpeed(Integer.parseInt(param2Str, 16));
|
||||
return codeForFI;
|
||||
}else if (cmdCode < 131) {
|
||||
// 预置位指令
|
||||
FrontEndControlCodeForPreset codeForPreset = new FrontEndControlCodeForPreset();
|
||||
switch (cmdCode) {
|
||||
case 0x81: // 设置预置位
|
||||
codeForPreset.setCode(1);
|
||||
break;
|
||||
case 0x82: // 调用预置位
|
||||
codeForPreset.setCode(2);
|
||||
break;
|
||||
case 0x83: // 删除预置位
|
||||
codeForPreset.setCode(3);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
// 预置位编号
|
||||
String param2Str = cmdStr.substring(10, 12);
|
||||
codeForPreset.setPresetId(Integer.parseInt(param2Str, 16));
|
||||
return codeForPreset;
|
||||
}else if (cmdCode < 136) {
|
||||
// 巡航指令
|
||||
FrontEndControlCodeForTour codeForTour = new FrontEndControlCodeForTour();
|
||||
String param3Str = cmdStr.substring(12, 13);
|
||||
switch (cmdCode) {
|
||||
case 0x84: // 加入巡航点
|
||||
codeForTour.setCode(1);
|
||||
break;
|
||||
case 0x85: // 删除一个巡航点
|
||||
codeForTour.setCode(2);
|
||||
break;
|
||||
case 0x86: // 设置巡航速度
|
||||
codeForTour.setCode(3);
|
||||
codeForTour.setTourSpeed(Integer.parseInt(param3Str, 16));
|
||||
break;
|
||||
case 0x87: // 设置巡航停留时间
|
||||
codeForTour.setCode(4);
|
||||
codeForTour.setTourTime(Integer.parseInt(param3Str, 16));
|
||||
break;
|
||||
case 0x88: // 开始巡航
|
||||
codeForTour.setCode(5);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
String param1Str = cmdStr.substring(8, 10);
|
||||
codeForTour.setTourId(Integer.parseInt(param1Str, 16));
|
||||
String param2Str = cmdStr.substring(10, 12);
|
||||
codeForTour.setPresetId(Integer.parseInt(param2Str, 16));
|
||||
return codeForTour;
|
||||
}else if (cmdCode < 138) {
|
||||
// 扫描指令
|
||||
FrontEndControlCodeForScan controlCodeForScan = new FrontEndControlCodeForScan();
|
||||
String param2Str = cmdStr.substring(10, 11);
|
||||
int param2Code = Integer.parseInt(param2Str, 16);
|
||||
switch (cmdCode) {
|
||||
case 0x89:
|
||||
switch (param2Code) {
|
||||
case 0x00: // 开始自动扫描
|
||||
controlCodeForScan.setCode(1);
|
||||
break;
|
||||
case 0x01: // 设置自动扫描左边界
|
||||
controlCodeForScan.setCode(2);
|
||||
break;
|
||||
case 0x02: // 设置自动扫描右边界
|
||||
controlCodeForScan.setCode(3);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x8A: // 删除一个巡航点
|
||||
controlCodeForScan.setCode(4);
|
||||
String param3Str = cmdStr.substring(12, 13);
|
||||
controlCodeForScan.setScanSpeed(Integer.parseInt(param3Str, 16));
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
String param1Str = cmdStr.substring(8, 10);
|
||||
controlCodeForScan.setScanId(Integer.parseInt(param1Str, 16));
|
||||
return controlCodeForScan;
|
||||
}else if (cmdCode < 141) {
|
||||
// 辅助开关
|
||||
FrontEndControlCodeForAuxiliary codeForAuxiliary = new FrontEndControlCodeForAuxiliary();
|
||||
switch (cmdCode) {
|
||||
case 0x8C: // 开
|
||||
codeForAuxiliary.setCode(1);
|
||||
break;
|
||||
case 0x8D: // 关
|
||||
codeForAuxiliary.setCode(2);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
// 预置位编号
|
||||
String param2Str = cmdStr.substring(10, 12);
|
||||
codeForAuxiliary.setAuxiliaryId(Integer.parseInt(param2Str, 16));
|
||||
return codeForAuxiliary;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class FrontEndControlCodeForAuxiliary implements IFrontEndControlCode {
|
||||
|
||||
private final FrontEndControlType type = FrontEndControlType.AUXILIARY;
|
||||
|
||||
@Override
|
||||
public FrontEndControlType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助开关控制指令: 1为开, 2为关, 3为设置自动扫描右边界, 4为设置自动扫描速度
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 辅助开关编号
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer auxiliaryId;
|
||||
|
||||
@Override
|
||||
public String encode() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class FrontEndControlCodeForFI implements IFrontEndControlCode {
|
||||
|
||||
private final FrontEndControlType type = FrontEndControlType.FI;
|
||||
|
||||
@Override
|
||||
public FrontEndControlType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 光圈,0为缩小 1为放大
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer iris;
|
||||
|
||||
/**
|
||||
* 聚焦 0 近, 1远
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer focus;
|
||||
|
||||
/**
|
||||
* 聚焦速度
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer focusSpeed;
|
||||
|
||||
/**
|
||||
* 光圈速度
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer irisSpeed;
|
||||
|
||||
@Override
|
||||
public String encode() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class FrontEndControlCodeForPTZ implements IFrontEndControlCode {
|
||||
|
||||
private final FrontEndControlType type = FrontEndControlType.PTZ;
|
||||
|
||||
@Override
|
||||
public FrontEndControlType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 镜头变倍,0为缩小 1为放大
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer zoom;
|
||||
|
||||
/**
|
||||
* 云台垂直方向控制 0 为上, 1为下
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer tilt;
|
||||
|
||||
/**
|
||||
* 云台水平方向控制 0 为左, 1为右
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer pan;
|
||||
|
||||
/**
|
||||
* 水平控制速度相对值
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer panSpeed;
|
||||
|
||||
/**
|
||||
* 垂直控制速度相对值
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer tiltSpeed;
|
||||
|
||||
/**
|
||||
* 变倍控制速度相对值
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer zoomSpeed;
|
||||
|
||||
@Override
|
||||
public String encode() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class FrontEndControlCodeForPreset implements IFrontEndControlCode {
|
||||
|
||||
private final FrontEndControlType type = FrontEndControlType.PRESET;
|
||||
|
||||
@Override
|
||||
public FrontEndControlType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 预置位指令: 1为设置预置位, 2为调用预置位, 3为删除预置位
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 预置位编号
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer presetId;
|
||||
|
||||
|
||||
@Override
|
||||
public String encode() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class FrontEndControlCodeForScan implements IFrontEndControlCode {
|
||||
|
||||
private final FrontEndControlType type = FrontEndControlType.SCAN;
|
||||
|
||||
@Override
|
||||
public FrontEndControlType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 预置位指令: 1为开始自动扫描, 2为设置自动扫描左边界, 3为设置自动扫描右边界, 4为设置自动扫描速度
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 自动扫描速度
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer scanSpeed;
|
||||
|
||||
/**
|
||||
* 扫描组号
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer scanId;
|
||||
|
||||
@Override
|
||||
public String encode() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class FrontEndControlCodeForTour implements IFrontEndControlCode {
|
||||
|
||||
private final FrontEndControlType type = FrontEndControlType.TOUR;
|
||||
|
||||
@Override
|
||||
public FrontEndControlType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 巡航指令: 1为加入巡航点, 2为删除一个巡航点, 3为设置巡航速度, 4为设置巡航停留时间, 5为开始巡航
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 巡航点
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer tourId;
|
||||
|
||||
/**
|
||||
* 巡航停留时间
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer tourTime;
|
||||
|
||||
/**
|
||||
* 巡航速度
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer tourSpeed;
|
||||
|
||||
/**
|
||||
* 预置位编号
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer presetId;
|
||||
|
||||
@Override
|
||||
public String encode() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
public enum FrontEndControlType {
|
||||
|
||||
PTZ,FI,PRESET,TOUR,SCAN,AUXILIARY
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
public interface IFrontEndControlCode {
|
||||
|
||||
FrontEndControlType getType();
|
||||
String encode();
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class PtzController {
|
||||
private IDeviceService deviceService;
|
||||
|
||||
@Autowired
|
||||
private IPTZService iptzService;
|
||||
private IPTZService ptzService;
|
||||
|
||||
@Autowired
|
||||
private DeferredResultHolder resultHolder;
|
||||
@@ -69,7 +69,7 @@ public class PtzController {
|
||||
|
||||
Assert.notNull(device, "设备[" + deviceId + "]不存在");
|
||||
|
||||
iptzService.frontEndCommand(device, channelId, cmdCode, parameter1, parameter2, combindCode2);
|
||||
ptzService.frontEndCommand(device, channelId, cmdCode, parameter1, parameter2, combindCode2);
|
||||
}
|
||||
|
||||
@Operation(summary = "云台控制", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
package com.genersoft.iot.vmp.gb28181.service;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.common.enums.DeviceControlType;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
|
||||
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelReduce;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
|
||||
import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import org.dom4j.Element;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -125,6 +131,8 @@ public interface IDeviceChannelService {
|
||||
|
||||
List<Integer> queryChaneIdListByDeviceDbIds(List<Integer> deviceDbId);
|
||||
|
||||
void handlePtzCmd(@NotNull Integer dataDeviceId, @NotNull Integer gbId, Element rootElement, DeviceControlType type, ErrorCallback<String> callback);
|
||||
|
||||
void queryRecordInfo(Device device, DeviceChannel channel, String startTime, String endTime, ErrorCallback<RecordInfo> object);
|
||||
|
||||
void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback<RecordInfo> object);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.genersoft.iot.vmp.gb28181.service;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.FrontEndControlCodeForPTZ;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
|
||||
public interface IGbChannelControlService {
|
||||
|
||||
|
||||
void ptz(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
|
||||
void fi(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
|
||||
void preset(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
|
||||
void tour(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
|
||||
void scan(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
|
||||
void auxiliary(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.InviteInfo;
|
||||
import com.genersoft.iot.vmp.common.InviteSessionType;
|
||||
import com.genersoft.iot.vmp.common.enums.ChannelDataType;
|
||||
import com.genersoft.iot.vmp.common.enums.DeviceControlType;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
@@ -22,6 +23,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
@@ -30,6 +32,7 @@ import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -41,11 +44,18 @@ import org.springframework.util.ObjectUtils;
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.SipException;
|
||||
import java.text.ParseException;
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.message.Response;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.text.ParseException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
|
||||
|
||||
/**
|
||||
* @author lin
|
||||
*/
|
||||
@@ -101,6 +111,10 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ISIPCommander cmder;
|
||||
|
||||
|
||||
@Override
|
||||
public int updateChannels(Device device, List<DeviceChannel> channels) {
|
||||
List<DeviceChannel> addChannels = new ArrayList<>();
|
||||
@@ -389,6 +403,39 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
|
||||
return channelMapper.queryChaneIdListByDeviceDbIds(deviceDbIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePtzCmd(@NotNull Integer dataDeviceId, @NotNull Integer gbId, Element rootElement, DeviceControlType type, ErrorCallback<String> callback) {
|
||||
|
||||
// 根据通道ID,获取所属设备
|
||||
Device device = deviceMapper.query(dataDeviceId);
|
||||
if (device == null) {
|
||||
// 不存在则回复404
|
||||
log.warn("[INFO 消息] 通道所属设备不存在, 设备ID: {}", dataDeviceId);
|
||||
callback.run(Response.NOT_FOUND, "device not found", null);
|
||||
return;
|
||||
}
|
||||
|
||||
DeviceChannel deviceChannel = channelMapper.getOneForSource(gbId);
|
||||
if (deviceChannel == null) {
|
||||
log.warn("[deviceControl] 未找到设备原始通道, 设备: {}({}),通道编号:{}", device.getName(),
|
||||
device.getDeviceId(), gbId);
|
||||
callback.run(Response.NOT_FOUND, "channel not found", null);
|
||||
return;
|
||||
}
|
||||
log.info("[deviceControl] 命令: {}, 设备: {}({}), 通道{}({}", type, device.getName(), device.getDeviceId(),
|
||||
deviceChannel.getName(), deviceChannel.getDeviceId());
|
||||
String cmdString = getText(rootElement, type.getVal());
|
||||
try {
|
||||
cmder.fronEndCmd(device, deviceChannel.getDeviceId(), cmdString, errorResult->{
|
||||
callback.run(errorResult.statusCode, errorResult.msg, null);
|
||||
}, errorResult->{
|
||||
callback.run(errorResult.statusCode, errorResult.msg, null);
|
||||
});
|
||||
} catch (InvalidArgumentException | SipException | ParseException e) {
|
||||
log.error("[命令发送失败] 云台/前端: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannelGPS(Device device, DeviceChannel deviceChannel, MobilePosition mobilePosition) {
|
||||
if (userSetting.getSavePositionHistory()) {
|
||||
|
||||
@@ -200,8 +200,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
||||
log.warn("[设备不存在] device:{}", deviceId);
|
||||
return;
|
||||
}
|
||||
log.info("[设备离线] device:{}, 当前心跳间隔: {}, 上次心跳时间:{}, 上次注册时间: {}", deviceId,
|
||||
device.getHeartBeatInterval(), device.getKeepaliveTime(), device.getRegisterTime());
|
||||
log.info("[设备离线] device:{}, 心跳间隔: {},心跳超时次数: {}, 上次心跳时间:{}, 上次注册时间: {}", deviceId,
|
||||
device.getHeartBeatInterval(), device.getHeartBeatCount(), device.getKeepaliveTime(), device.getRegisterTime());
|
||||
String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + deviceId;
|
||||
dynamicTask.stop(registerExpireTaskKey);
|
||||
if (device.isOnLine()) {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.genersoft.iot.vmp.gb28181.service.impl;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.FrontEndControlCodeForPTZ;
|
||||
import com.genersoft.iot.vmp.gb28181.service.IGbChannelControlService;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class GbChannelControlServiceImpl implements IGbChannelControlService {
|
||||
|
||||
@Override
|
||||
public void ptz(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
|
||||
log.info("[通用通道] 云台控制, 通道: {}", channel.getGbId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preset(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
|
||||
log.info("[通用通道] 预置位, 通道: {}", channel.getGbId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fi(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
|
||||
log.info("[通用通道] FI指令, 通道: {}", channel.getGbId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tour(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scan(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void auxiliary(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ public class SipInviteSessionManager {
|
||||
if (ssrcTransaction == null ) {
|
||||
return;
|
||||
}
|
||||
redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_STREAM + userSetting.getServerId(), stream);
|
||||
redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_STREAM + userSetting.getServerId(), app + stream);
|
||||
if (ssrcTransaction.getCallId() != null) {
|
||||
redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_CALL_ID + userSetting.getServerId(), ssrcTransaction.getCallId());
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public class SipInviteSessionManager {
|
||||
}
|
||||
redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_CALL_ID + userSetting.getServerId(), callId);
|
||||
if (ssrcTransaction.getStream() != null) {
|
||||
redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_STREAM + userSetting.getServerId(), ssrcTransaction.getStream());
|
||||
redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_STREAM + userSetting.getServerId(), ssrcTransaction.getApp() + ssrcTransaction.getStream());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -218,9 +218,6 @@ public class SIPCommander implements ISIPCommander {
|
||||
ptzXml.append("</Info>\r\n");
|
||||
ptzXml.append("</Control>\r\n");
|
||||
|
||||
|
||||
|
||||
|
||||
SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService;
|
||||
import com.genersoft.iot.vmp.gb28181.service.IDeviceService;
|
||||
import com.genersoft.iot.vmp.gb28181.service.IGbChannelControlService;
|
||||
import com.genersoft.iot.vmp.gb28181.service.IGbChannelService;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
||||
@@ -43,6 +44,9 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
|
||||
@Autowired
|
||||
private IGbChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private IGbChannelControlService channelControlService;
|
||||
|
||||
@Autowired
|
||||
private IDeviceService deviceService;
|
||||
|
||||
@@ -136,49 +140,91 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
|
||||
* 处理云台指令
|
||||
*/
|
||||
private void handlePtzCmd(CommonGBChannel channel, Element rootElement, SIPRequest request, DeviceControlType type) {
|
||||
if (channel.getDataType() != ChannelDataType.GB28181.value) {
|
||||
// 只支持国标的云台控制
|
||||
log.warn("[INFO 消息] 只支持国标的云台控制, 通道ID: {}", channel.getGbId());
|
||||
try {
|
||||
responseAck(request, Response.FORBIDDEN, "");
|
||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||
log.error("[命令发送失败] 错误信息: {}", e.getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 根据通道ID,获取所属设备
|
||||
Device device = deviceService.getDevice(channel.getDataDeviceId());
|
||||
if (device == null) {
|
||||
// 不存在则回复404
|
||||
log.warn("[INFO 消息] 通道所属设备不存在, 通道ID: {}", channel.getGbId());
|
||||
try {
|
||||
responseAck(request, Response.NOT_FOUND, "device not found");
|
||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||
log.error("[命令发送失败] 错误信息: {}", e.getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (channel.getDataType() == ChannelDataType.GB28181.value) {
|
||||
|
||||
DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channel.getGbId());
|
||||
if (deviceChannel == null) {
|
||||
log.warn("[deviceControl] 未找到设备原始通道, 设备: {}({}),通道编号:{}", device.getName(),
|
||||
device.getDeviceId(), channel.getGbId());
|
||||
try {
|
||||
responseAck(request, Response.NOT_FOUND, "channel not found");
|
||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||
log.error("[命令发送失败] 错误信息: {}", e.getMessage());
|
||||
deviceChannelService.handlePtzCmd(channel.getDataDeviceId(), channel.getGbId(), rootElement, type, ((code, msg, data) -> {
|
||||
try {
|
||||
responseAck(request, code, msg);
|
||||
} catch (InvalidArgumentException | SipException | ParseException exception) {
|
||||
log.error("[命令发送失败] 云台指令: {}", exception.getMessage());
|
||||
}
|
||||
}));
|
||||
}else {
|
||||
// 解析云台控制参数
|
||||
String cmdString = getText(rootElement, type.getVal());
|
||||
IFrontEndControlCode frontEndControlCode = FrontEndCode.decode(cmdString);
|
||||
if (frontEndControlCode == null) {
|
||||
log.info("[INFO 消息] 不支持的控制方式");
|
||||
try {
|
||||
responseAck(request, Response.FORBIDDEN, "");
|
||||
} catch (InvalidArgumentException | SipException | ParseException exception) {
|
||||
log.error("[命令发送失败] 云台指令: {}", exception.getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch (frontEndControlCode.getType()){
|
||||
case PTZ:
|
||||
channelControlService.ptz(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> {
|
||||
try {
|
||||
responseAck(request, code, msg);
|
||||
} catch (InvalidArgumentException | SipException | ParseException exception) {
|
||||
log.error("[命令发送失败] 云台指令: {}", exception.getMessage());
|
||||
}
|
||||
}));
|
||||
break;
|
||||
case FI:
|
||||
channelControlService.fi(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> {
|
||||
try {
|
||||
responseAck(request, code, msg);
|
||||
} catch (InvalidArgumentException | SipException | ParseException exception) {
|
||||
log.error("[命令发送失败] 云台指令: {}", exception.getMessage());
|
||||
}
|
||||
}));
|
||||
break;
|
||||
case PRESET:
|
||||
channelControlService.preset(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> {
|
||||
try {
|
||||
responseAck(request, code, msg);
|
||||
} catch (InvalidArgumentException | SipException | ParseException exception) {
|
||||
log.error("[命令发送失败] 云台指令: {}", exception.getMessage());
|
||||
}
|
||||
}));
|
||||
break;
|
||||
case TOUR:
|
||||
channelControlService.tour(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> {
|
||||
try {
|
||||
responseAck(request, code, msg);
|
||||
} catch (InvalidArgumentException | SipException | ParseException exception) {
|
||||
log.error("[命令发送失败] 云台指令: {}", exception.getMessage());
|
||||
}
|
||||
}));
|
||||
break;
|
||||
case SCAN:
|
||||
channelControlService.scan(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> {
|
||||
try {
|
||||
responseAck(request, code, msg);
|
||||
} catch (InvalidArgumentException | SipException | ParseException exception) {
|
||||
log.error("[命令发送失败] 云台指令: {}", exception.getMessage());
|
||||
}
|
||||
}));
|
||||
break;
|
||||
case AUXILIARY:
|
||||
channelControlService.auxiliary(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> {
|
||||
try {
|
||||
responseAck(request, code, msg);
|
||||
} catch (InvalidArgumentException | SipException | ParseException exception) {
|
||||
log.error("[命令发送失败] 云台指令: {}", exception.getMessage());
|
||||
}
|
||||
}));
|
||||
break;
|
||||
default:
|
||||
log.info("[INFO 消息] 设备不支持的控制方式");
|
||||
try {
|
||||
responseAck(request, Response.FORBIDDEN, "");
|
||||
} catch (InvalidArgumentException | SipException | ParseException exception) {
|
||||
log.error("[命令发送失败] 云台指令: {}", exception.getMessage());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
log.info("[deviceControl] 命令: {}, 设备: {}({}), 通道{}({}", type, device.getName(), device.getDeviceId(),
|
||||
deviceChannel.getName(), deviceChannel.getDeviceId());
|
||||
String cmdString = getText(rootElement, type.getVal());
|
||||
try {
|
||||
cmder.fronEndCmd(device, deviceChannel.getDeviceId(), cmdString,
|
||||
errorResult -> onError(request, errorResult),
|
||||
okResult -> onOk(request));
|
||||
} catch (InvalidArgumentException | SipException | ParseException e) {
|
||||
log.error("[命令发送失败] 云台/前端: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,8 +140,6 @@ public class MediaServiceImpl implements IMediaService {
|
||||
result.setEnable_mp4(userSetting.getRecordSip());
|
||||
}
|
||||
|
||||
result.setEnable_mp4(inviteInfo.getRecord());
|
||||
|
||||
// 单端口模式下修改流 ID
|
||||
if (!mediaServer.isRtpEnable() && inviteInfo == null) {
|
||||
String ssrc = String.format("%010d", Long.parseLong(stream, 16));
|
||||
|
||||
@@ -2,9 +2,14 @@ package com.genersoft.iot.vmp.streamProxy.service.impl;
|
||||
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.media.bean.MediaInfo;
|
||||
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||
import com.genersoft.iot.vmp.media.event.hook.Hook;
|
||||
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.event.hook.HookType;
|
||||
import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
|
||||
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService;
|
||||
@@ -24,6 +29,7 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.sip.message.Response;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
@@ -39,6 +45,12 @@ public class StreamProxyPlayServiceImpl implements IStreamProxyPlayService {
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private HookSubscribe subscribe;
|
||||
|
||||
@Autowired
|
||||
private DynamicTask dynamicTask;
|
||||
|
||||
@Autowired
|
||||
private UserSetting userSetting;
|
||||
|
||||
@@ -103,7 +115,26 @@ public class StreamProxyPlayServiceImpl implements IStreamProxyPlayService {
|
||||
streamProxy.setEnableMp4(record);
|
||||
}
|
||||
|
||||
return startProxy(streamProxy);
|
||||
StreamInfo streamInfo = startProxy(streamProxy);
|
||||
if (callback != null) {
|
||||
// 设置流超时的定时任务
|
||||
String timeOutTaskKey = UUID.randomUUID().toString();
|
||||
Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, streamProxy.getApp(), streamProxy.getStream(), streamInfo.getMediaServer().getId());
|
||||
dynamicTask.startDelay(timeOutTaskKey, () -> {
|
||||
// 收流超时
|
||||
subscribe.removeSubscribe(rtpHook);
|
||||
callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), streamInfo);
|
||||
}, userSetting.getPlayTimeout());
|
||||
|
||||
// 开启流到来的监听
|
||||
subscribe.addSubscribe(rtpHook, (hookData) -> {
|
||||
dynamicTask.stop(timeOutTaskKey);
|
||||
// hook响应
|
||||
callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
|
||||
subscribe.removeSubscribe(rtpHook);
|
||||
});
|
||||
}
|
||||
return streamInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user