Merge branch 'master' into develop-add-api-key

pull/1389/head
leesam 2024-04-01 09:19:46 +08:00
commit 23beb4fde0
43 changed files with 514 additions and 250 deletions

View File

@ -112,6 +112,7 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
# 非开源的内容 # 非开源的内容
- [X] ONVIF设备的接入支持点播云台控制国标级联点播自动点播。在[知识星球](https://t.zsxq.com/10WAnH2MP)放了试用安装包以及使用教程,没有使用时间限制,需要源码可以星球私信我或者邮箱联系。 - [X] ONVIF设备的接入支持点播云台控制国标级联点播自动点播。在[知识星球](https://t.zsxq.com/10WAnH2MP)放了试用安装包以及使用教程,没有使用时间限制,需要源码可以星球私信我或者邮箱联系。
- [X] 支持国标28181-2022协议支持巡航轨迹查询PTZ精准控制存储卡格式化设备软件升级OSD配置h265+aac支持辅码流录像倒放等。具体的功能列表可在[知识星球](https://t.zsxq.com/18GXkpkqs)查看,需要源码和测试可以在星球私信联系或者发邮件给我
# 授权协议 # 授权协议
@ -119,7 +120,7 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
# 技术支持 # 技术支持
[知识星球](https://t.zsxq.com/0d8VAD3Dm)专栏列表: [知识星球](https://t.zsxq.com/0d8VAD3Dm)专栏列表:
- [使用入门系列一WVP-PRO能做什么](https://t.zsxq.com/0dLguVoSp) - [使用入门系列一WVP-PRO能做什么](https://t.zsxq.com/0dLguVoSp)
有偿技术支持请发送邮件到648540858@qq.com 有偿技术支持请发送邮件到648540858@qq.com

View File

@ -9,6 +9,7 @@ import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.time.Instant; import java.time.Instant;
import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -59,7 +60,8 @@ public class DynamicTask {
} }
} }
// scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period cycleForCatalog表示执行的间隔 // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period cycleForCatalog表示执行的间隔
future = threadPoolTaskScheduler.scheduleAtFixedRate(task, cycleForCatalog);
future = threadPoolTaskScheduler.scheduleAtFixedRate(task, new Date(System.currentTimeMillis() + cycleForCatalog), cycleForCatalog);
if (future != null){ if (future != null){
futureMap.put(key, future); futureMap.put(key, future);
runnableMap.put(key, task); runnableMap.put(key, task);

View File

@ -142,13 +142,13 @@ public class DeviceChannel {
* *
*/ */
@Schema(description = "云台类型") @Schema(description = "云台类型")
private int PTZType; private int ptzType;
/** /**
* *
*/ */
@Schema(description = "云台类型描述字符串") @Schema(description = "云台类型描述字符串")
private String PTZTypeText; private String ptzTypeText;
/** /**
* *
@ -266,23 +266,23 @@ public class DeviceChannel {
this.deviceId = deviceId; this.deviceId = deviceId;
} }
public void setPTZType(int PTZType) { public void setPtzType(int ptzType) {
this.PTZType = PTZType; this.ptzType = ptzType;
switch (PTZType) { switch (ptzType) {
case 0: case 0:
this.PTZTypeText = "未知"; this.ptzTypeText = "未知";
break; break;
case 1: case 1:
this.PTZTypeText = "球机"; this.ptzTypeText = "球机";
break; break;
case 2: case 2:
this.PTZTypeText = "半球"; this.ptzTypeText = "半球";
break; break;
case 3: case 3:
this.PTZTypeText = "固定枪机"; this.ptzTypeText = "固定枪机";
break; break;
case 4: case 4:
this.PTZTypeText = "遥控枪机"; this.ptzTypeText = "遥控枪机";
break; break;
} }
} }
@ -447,16 +447,16 @@ public class DeviceChannel {
this.password = password; this.password = password;
} }
public int getPTZType() { public int getPtzType() {
return PTZType; return ptzType;
} }
public String getPTZTypeText() { public String getPtzTypeText() {
return PTZTypeText; return ptzTypeText;
} }
public void setPTZTypeText(String PTZTypeText) { public void setPtzTypeText(String ptzTypeText) {
this.PTZTypeText = PTZTypeText; this.ptzTypeText = ptzTypeText;
} }
public boolean isStatus() { public boolean isStatus() {

View File

@ -103,6 +103,16 @@ public class SubscribeHolder {
return platforms; return platforms;
} }
public List<String> getAllMobilePositionSubscribePlatform() {
List<String> platforms = new ArrayList<>();
if(!mobilePositionMap.isEmpty()) {
for (String key : mobilePositionMap.keySet()) {
platforms.add(mobilePositionMap.get(key).getId());
}
}
return platforms;
}
public void removeAllSubscribe(String platformId) { public void removeAllSubscribe(String platformId) {
removeMobilePositionSubscribe(platformId); removeMobilePositionSubscribe(platformId);
removeCatalogSubscribe(platformId); removeCatalogSubscribe(platformId);

View File

@ -4,6 +4,7 @@ import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent; import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent;
import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent; import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition.MobilePositionEvent;
import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent; import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent;
import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent; import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -94,6 +95,13 @@ public class EventPublisher {
} }
public void mobilePositionEventPublish(MobilePosition mobilePosition) {
MobilePositionEvent event = new MobilePositionEvent(this);
event.setMobilePosition(mobilePosition);
applicationEventPublisher.publishEvent(event);
}
public void catalogEventPublishForStream(String platformId, List<GbStream> gbStreams, String type) { public void catalogEventPublishForStream(String platformId, List<GbStream> gbStreams, String type) {
CatalogEvent outEvent = new CatalogEvent(this); CatalogEvent outEvent = new CatalogEvent(this);
outEvent.setGbStreams(gbStreams); outEvent.setGbStreams(gbStreams);

View File

@ -0,0 +1,20 @@
package com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import org.springframework.context.ApplicationEvent;
public class MobilePositionEvent extends ApplicationEvent {
public MobilePositionEvent(Object source) {
super(source);
}
private MobilePosition mobilePosition;
public MobilePosition getMobilePosition() {
return mobilePosition;
}
public void setMobilePosition(MobilePosition mobilePosition) {
this.mobilePosition = mobilePosition;
}
}

View File

@ -0,0 +1,61 @@
package com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import java.text.ParseException;
import java.util.List;
/**
*
*/
@Component
public class MobilePositionEventLister implements ApplicationListener<MobilePositionEvent> {
private final static Logger logger = LoggerFactory.getLogger(MobilePositionEventLister.class);
@Autowired
private IVideoManagerStorage storager;
@Autowired
private SIPCommanderFroPlatform sipCommanderFroPlatform;
@Autowired
private SubscribeHolder subscribeHolder;
@Override
public void onApplicationEvent(MobilePositionEvent event) {
// 获取所用订阅
List<String> platforms = subscribeHolder.getAllMobilePositionSubscribePlatform();
if (platforms.isEmpty()) {
return;
}
List<ParentPlatform> parentPlatformsForGB = storager.queryPlatFormListForGBWithGBId(event.getMobilePosition().getChannelId(), platforms);
for (ParentPlatform platform : parentPlatformsForGB) {
logger.info("[向上级发送MobilePosition] 通道:{},平台:{} 位置: {}:{}", event.getMobilePosition().getChannelId(),
platform.getServerGBId(), event.getMobilePosition().getLongitude(), event.getMobilePosition().getLatitude());
SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId());
try {
sipCommanderFroPlatform.sendNotifyMobilePosition(platform, GPSMsgInfo.getInstance(event.getMobilePosition()),
subscribe);
} catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException |
IllegalAccessException e) {
logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage());
}
}
}
}

View File

@ -50,7 +50,7 @@ public class VideoStreamSessionManager {
ssrcTransaction.setType(type); ssrcTransaction.setType(type);
redisTemplate.opsForValue().set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() redisTemplate.opsForValue().set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId()
+ "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction); + ":" + deviceId + ":" + channelId + ":" + callId + ":" + stream, ssrcTransaction);
} }
public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){ public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){
@ -67,7 +67,7 @@ public class VideoStreamSessionManager {
if (ObjectUtils.isEmpty(stream)) { if (ObjectUtils.isEmpty(stream)) {
stream ="*"; stream ="*";
} }
String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":" + deviceId + ":" + channelId + ":" + callId+ ":" + stream;
List<Object> scanResult = RedisUtil.scan(redisTemplate, key); List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
if (scanResult.size() == 0) { if (scanResult.size() == 0) {
return null; return null;
@ -80,12 +80,12 @@ public class VideoStreamSessionManager {
if (ObjectUtils.isEmpty(callId)) { if (ObjectUtils.isEmpty(callId)) {
return null; return null;
} }
String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_" + callId+ "_*"; String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":*:*:" + callId+ ":*";
List<Object> scanResult = RedisUtil.scan(redisTemplate, key); List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
if (!scanResult.isEmpty()) { if (!scanResult.isEmpty()) {
return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0));
}else { }else {
key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_play_*"; key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":*:*:play:*";
scanResult = RedisUtil.scan(redisTemplate, key); scanResult = RedisUtil.scan(redisTemplate, key);
if (scanResult.isEmpty()) { if (scanResult.isEmpty()) {
return null; return null;
@ -115,7 +115,7 @@ public class VideoStreamSessionManager {
if (ObjectUtils.isEmpty(stream)) { if (ObjectUtils.isEmpty(stream)) {
stream ="*"; stream ="*";
} }
String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream; String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":" + deviceId + ":" + channelId + ":" + callId+ ":" + stream;
List<Object> scanResult = RedisUtil.scan(redisTemplate, key); List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
if (scanResult.size() == 0) { if (scanResult.size() == 0) {
return null; return null;
@ -149,8 +149,8 @@ public class VideoStreamSessionManager {
return; return;
} }
for (SsrcTransaction ssrcTransaction : ssrcTransactionList) { for (SsrcTransaction ssrcTransaction : ssrcTransactionList) {
redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":"
+ deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream()); + deviceId + ":" + channelId + ":" + ssrcTransaction.getCallId() + ":" + ssrcTransaction.getStream());
} }
} }
@ -159,8 +159,8 @@ public class VideoStreamSessionManager {
if (ssrcTransaction == null ) { if (ssrcTransaction == null ) {
return; return;
} }
redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + ":"
+ deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream()); + deviceId + ":" + channelId + ":" + ssrcTransaction.getCallId() + ":" + ssrcTransaction.getStream());
} }

View File

@ -220,13 +220,8 @@ public interface ISIPCommander {
/** /**
* *
* *
* @param device
* @param channelId id
* @param enabled 使1 = 0 =
* @param resetTime 使:(s)
* @param presetIndex 使0~255
*/ */
void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; void homePositionCmd(Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
/** /**
* *

View File

@ -880,7 +880,7 @@ public class SIPCommander implements ISIPCommander {
* @param presetIndex 使0~255 * @param presetIndex 使0~255
*/ */
@Override @Override
public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { public void homePositionCmd(Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
StringBuffer cmdXml = new StringBuffer(200); StringBuffer cmdXml = new StringBuffer(200);
String charset = device.getCharset(); String charset = device.getCharset();
@ -894,18 +894,10 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
} }
cmdXml.append("<HomePosition>\r\n"); cmdXml.append("<HomePosition>\r\n");
if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) { if (enabled) {
cmdXml.append("<Enabled>1</Enabled>\r\n"); cmdXml.append("<Enabled>1</Enabled>\r\n");
if (NumericUtil.isInteger(resetTime)) {
cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n"); cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
} else {
cmdXml.append("<ResetTime>0</ResetTime>\r\n");
}
if (NumericUtil.isInteger(presetIndex)) {
cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n"); cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
} else {
cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
}
} else { } else {
cmdXml.append("<Enabled>0</Enabled>\r\n"); cmdXml.append("<Enabled>0</Enabled>\r\n");
} }

View File

@ -358,8 +358,8 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
}else { }else {
catalogXml.append("<Password></Password>\r\n"); catalogXml.append("<Password></Password>\r\n");
} }
if (!ObjectUtils.isEmpty(channel.getPTZType())) { if (!ObjectUtils.isEmpty(channel.getPtzType())) {
catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n"); catalogXml.append("<PTZType>" + channel.getPtzType() + "</PTZType>\r\n");
}else { }else {
catalogXml.append("<PTZType></PTZType>\r\n"); catalogXml.append("<PTZType></PTZType>\r\n");
} }

View File

@ -15,8 +15,11 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.*; import com.genersoft.iot.vmp.service.*;
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
import com.genersoft.iot.vmp.service.bean.RequestStopPushStreamMsg;
import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import gov.nist.javax.sip.message.SIPRequest; import gov.nist.javax.sip.message.SIPRequest;
@ -92,6 +95,12 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
@Autowired @Autowired
private UserSetting userSetting; private UserSetting userSetting;
@Autowired
private IStreamPushService pushService;
@Autowired
private RedisGbPlayMsgListener redisGbPlayMsgListener;
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅 // 添加消息处理的订阅
@ -115,7 +124,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
// 收流端发送的停止 // 收流端发送的停止
if (sendRtpItem != null){ if (sendRtpItem != null){
logger.info("[收到bye] 来自{},停止通道:{}, 类型: {}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), sendRtpItem.getPlayType()); logger.info("[收到bye] 来自{},停止通道:{}, 类型: {}, callId: {}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), sendRtpItem.getPlayType(), callIdHeader.getCallId());
String streamId = sendRtpItem.getStream(); String streamId = sendRtpItem.getStream();
Map<String, Object> param = new HashMap<>(); Map<String, Object> param = new HashMap<>();
@ -123,7 +132,19 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
param.put("app",sendRtpItem.getApp()); param.put("app",sendRtpItem.getApp());
param.put("stream",streamId); param.put("stream",streamId);
param.put("ssrc",sendRtpItem.getSsrc()); param.put("ssrc",sendRtpItem.getSsrc());
logger.info("[收到bye] 停止推流:{}", streamId); logger.info("[收到bye] 停止推流:{}, 媒体节点: {}", streamId, sendRtpItem.getMediaServerId());
if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) {
// 查询这路流是否是本平台的
StreamPushItem push = pushService.getPush(sendRtpItem.getApp(), sendRtpItem.getStream());
if (push!= null && !push.isSelf()) {
// 不是本平台的就发送redis消息让其他wvp停止发流
ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId());
if (platform != null) {
RequestStopPushStreamMsg streamMsg = RequestStopPushStreamMsg.getInstance(sendRtpItem, platform.getName(), platform.getId());
redisGbPlayMsgListener.sendMsgForStopSendRtpStream(sendRtpItem.getServerId(), streamMsg);
}
}else {
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(),
callIdHeader.getCallId(), null); callIdHeader.getCallId(), null);
@ -131,7 +152,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
if (userSetting.getUseCustomSsrcForParentInvite()) { if (userSetting.getUseCustomSsrcForParentInvite()) {
mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc()); mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc());
} }
if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) {
ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId()); ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId());
if (platform != null) { if (platform != null) {
MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
@ -143,7 +164,17 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
logger.info("[上级平台停止观看] 未找到平台{}的信息发送redis消息失败", sendRtpItem.getPlatformId()); logger.info("[上级平台停止观看] 未找到平台{}的信息发送redis消息失败", sendRtpItem.getPlatformId());
} }
} }
}else {
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(),
callIdHeader.getCallId(), null);
zlmServerFactory.stopSendRtpStream(mediaInfo, param);
if (userSetting.getUseCustomSsrcForParentInvite()) {
mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc());
}
}
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
if (mediaInfo != null) {
AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
if (audioBroadcastCatch != null && audioBroadcastCatch.getSipTransactionInfo().getCallId().equals(callIdHeader.getCallId())) { if (audioBroadcastCatch != null && audioBroadcastCatch.getSipTransactionInfo().getCallId().equals(callIdHeader.getCallId())) {
// 来自上级平台的停止对讲 // 来自上级平台的停止对讲
@ -169,6 +200,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
} }
} }
} }
}
// 可能是设备发送的停止 // 可能是设备发送的停止
SsrcTransaction ssrcTransaction = streamSession.getSsrcTransactionByCallId(callIdHeader.getCallId()); SsrcTransaction ssrcTransaction = streamSession.getSsrcTransactionByCallId(callIdHeader.getCallId());

View File

@ -498,6 +498,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
String endTimeStr = DateUtil.urlFormatter.format(end); String endTimeStr = DateUtil.urlFormatter.format(end);
String stream = device.getDeviceId() + "_" + channelId + "_" + startTimeStr + "_" + endTimeStr; String stream = device.getDeviceId() + "_" + channelId + "_" + startTimeStr + "_" + endTimeStr;
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, stream, null, device.isSsrcCheck(), true, 0,false, false, device.getStreamModeForParam()); SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, stream, null, device.isSsrcCheck(), true, 0,false, false, device.getStreamModeForParam());
sendRtpItem.setStream(stream);
// 写入redis 超时时回复 // 写入redis 超时时回复
redisCatchStorage.updateSendRTPSever(sendRtpItem); redisCatchStorage.updateSendRTPSever(sendRtpItem);
playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start), playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start),
@ -1006,7 +1007,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
Media media = mediaDescription.getMedia(); Media media = mediaDescription.getMedia();
Vector mediaFormats = media.getMediaFormats(false); Vector mediaFormats = media.getMediaFormats(false);
if (mediaFormats.contains("8")) { // if (mediaFormats.contains("8")) {
port = media.getMediaPort(); port = media.getMediaPort();
String protocol = media.getProtocol(); String protocol = media.getProtocol();
// 区分TCP发流还是udp 当前默认udp // 区分TCP发流还是udp 当前默认udp
@ -1022,7 +1023,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
} }
} }
break; break;
} // }
} }
if (port == -1) { if (port == -1) {
logger.info("不支持的媒体格式返回415"); logger.info("不支持的媒体格式返回415");

View File

@ -1,7 +1,5 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.bean.*;
@ -78,9 +76,6 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
@Autowired @Autowired
private NotifyRequestForCatalogProcessor notifyRequestForCatalogProcessor; private NotifyRequestForCatalogProcessor notifyRequestForCatalogProcessor;
@Autowired
private CivilCodeFileConf civilCodeFileConf;
private ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>(); private ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>();
@Qualifier("taskExecutor") @Qualifier("taskExecutor")
@ -98,7 +93,6 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
@Override @Override
public void process(RequestEvent evt) { public void process(RequestEvent evt) {
try { try {
if (taskQueue.size() >= userSetting.getMaxNotifyCountQueue()) { if (taskQueue.size() >= userSetting.getMaxNotifyCountQueue()) {
responseAck((SIPRequest) evt.getRequest(), Response.BUSY_HERE, null, null); responseAck((SIPRequest) evt.getRequest(), Response.BUSY_HERE, null, null);
logger.error("[notify] 待处理消息队列已满 {}返回486 BUSY_HERE消息不做处理", userSetting.getMaxNotifyCountQueue()); logger.error("[notify] 待处理消息队列已满 {}返回486 BUSY_HERE消息不做处理", userSetting.getMaxNotifyCountQueue());
@ -234,25 +228,8 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02());
mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02());
if (userSetting.getSavePositionHistory()) { deviceChannelService.updateChannelGPS(device, deviceChannel, mobilePosition);
storager.insertMobilePosition(mobilePosition);
}
storager.updateChannelPosition(deviceChannel);
// 向关联了该通道并且开启移动位置订阅的上级平台发送移动位置订阅消息
// 发送redis消息。 通知位置信息的变化
JSONObject jsonObject = new JSONObject();
jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
jsonObject.put("serial", deviceId);
jsonObject.put("code", channelId);
jsonObject.put("longitude", mobilePosition.getLongitude());
jsonObject.put("latitude", mobilePosition.getLatitude());
jsonObject.put("altitude", mobilePosition.getAltitude());
jsonObject.put("direction", mobilePosition.getDirection());
jsonObject.put("speed", mobilePosition.getSpeed());
redisCatchStorage.sendMobilePositionMsg(jsonObject);
} catch (DocumentException e) { } catch (DocumentException e) {
logger.error("未处理的异常 ", e); logger.error("未处理的异常 ", e);
} }
@ -340,26 +317,9 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02());
mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02());
if (userSetting.getSavePositionHistory()) { deviceChannelService.updateChannelGPS(device, deviceChannel, mobilePosition);
storager.insertMobilePosition(mobilePosition);
} }
storager.updateChannelPosition(deviceChannel);
// 发送redis消息。 通知位置信息的变化
JSONObject jsonObject = new JSONObject();
jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
jsonObject.put("serial", deviceChannel.getDeviceId());
jsonObject.put("code", deviceChannel.getChannelId());
jsonObject.put("longitude", mobilePosition.getLongitude());
jsonObject.put("latitude", mobilePosition.getLatitude());
jsonObject.put("altitude", mobilePosition.getAltitude());
jsonObject.put("direction", mobilePosition.getDirection());
jsonObject.put("speed", mobilePosition.getSpeed());
redisCatchStorage.sendMobilePositionMsg(jsonObject);
}
// TODO: 需要实现存储报警信息、报警分类
// 回复200 OK // 回复200 OK
if (redisCatchStorage.deviceIsOnline(deviceId)) { if (redisCatchStorage.deviceIsOnline(deviceId)) {
publisher.deviceAlarmEventPublish(deviceAlarm); publisher.deviceAlarmEventPublish(deviceAlarm);

View File

@ -248,7 +248,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
HomePositionRequest homePosition = loadElement(rootElement, HomePositionRequest.class); HomePositionRequest homePosition = loadElement(rootElement, HomePositionRequest.class);
//获取整个消息主体,我们只需要修改请求头即可 //获取整个消息主体,我们只需要修改请求头即可
HomePositionRequest.HomePosition info = homePosition.getHomePosition(); HomePositionRequest.HomePosition info = homePosition.getHomePosition();
cmder.homePositionCmd(device, channelId, info.getEnabled(), info.getResetTime(), info.getPresetIndex(), cmder.homePositionCmd(device, channelId, !"0".equals(info.getEnabled()), Integer.parseInt(info.getResetTime()), Integer.parseInt(info.getPresetIndex()),
errorResult -> onError(request, errorResult), errorResult -> onError(request, errorResult),
okResult -> onOk(request, okResult)); okResult -> onOk(request, okResult));
} catch (Exception e) { } catch (Exception e) {

View File

@ -75,6 +75,9 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
@Autowired @Autowired
private ThreadPoolTaskExecutor taskExecutor; private ThreadPoolTaskExecutor taskExecutor;
@Autowired
private EventPublisher eventPublisher;
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
@ -158,22 +161,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02());
mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02());
if (userSetting.getSavePositionHistory()) { deviceChannelService.updateChannelGPS(device, deviceChannel, mobilePosition);
storager.insertMobilePosition(mobilePosition);
}
storager.updateChannelPosition(deviceChannel);
// 发送redis消息。 通知位置信息的变化
JSONObject jsonObject = new JSONObject();
jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
jsonObject.put("serial", deviceChannel.getDeviceId());
jsonObject.put("code", deviceChannel.getChannelId());
jsonObject.put("longitude", mobilePosition.getLongitude());
jsonObject.put("latitude", mobilePosition.getLatitude());
jsonObject.put("altitude", mobilePosition.getAltitude());
jsonObject.put("direction", mobilePosition.getDirection());
jsonObject.put("speed", mobilePosition.getSpeed());
redisCatchStorage.sendMobilePositionMsg(jsonObject);
} }
} }
if (!ObjectUtils.isEmpty(deviceAlarm.getDeviceId())) { if (!ObjectUtils.isEmpty(deviceAlarm.getDeviceId())) {

View File

@ -1,8 +1,8 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
@ -57,6 +57,9 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
@Autowired @Autowired
private IDeviceChannelService deviceChannelService; private IDeviceChannelService deviceChannelService;
@Autowired
private EventPublisher eventPublisher;
private ConcurrentLinkedQueue<SipMsgInfo> taskQueue = new ConcurrentLinkedQueue<>(); private ConcurrentLinkedQueue<SipMsgInfo> taskQueue = new ConcurrentLinkedQueue<>();
@Qualifier("taskExecutor") @Qualifier("taskExecutor")
@ -137,22 +140,7 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02());
mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02());
if (userSetting.getSavePositionHistory()) { deviceChannelService.updateChannelGPS(device, deviceChannel, mobilePosition);
storager.insertMobilePosition(mobilePosition);
}
storager.updateChannelPosition(deviceChannel);
// 发送redis消息。 通知位置信息的变化
JSONObject jsonObject = new JSONObject();
jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
jsonObject.put("serial", deviceChannel.getDeviceId());
jsonObject.put("code", deviceChannel.getChannelId());
jsonObject.put("longitude", mobilePosition.getLongitude());
jsonObject.put("latitude", mobilePosition.getLatitude());
jsonObject.put("altitude", mobilePosition.getAltitude());
jsonObject.put("direction", mobilePosition.getDirection());
jsonObject.put("speed", mobilePosition.getSpeed());
redisCatchStorage.sendMobilePositionMsg(jsonObject);
} catch (DocumentException e) { } catch (DocumentException e) {
logger.error("未处理的异常 ", e); logger.error("未处理的异常 ", e);

View File

@ -1,6 +1,5 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
@ -131,11 +130,7 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02()); mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02());
mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02()); mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02());
if (userSetting.getSavePositionHistory()) { deviceChannelService.updateChannelGPS(device, deviceChannel, mobilePosition);
storager.insertMobilePosition(mobilePosition);
}
storager.updateChannelPosition(deviceChannel);
String key = DeferredResultHolder.CALLBACK_CMD_MOBILE_POSITION + device.getDeviceId(); String key = DeferredResultHolder.CALLBACK_CMD_MOBILE_POSITION + device.getDeviceId();
RequestMessage msg = new RequestMessage(); RequestMessage msg = new RequestMessage();
@ -143,17 +138,6 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
msg.setData(mobilePosition); msg.setData(mobilePosition);
resultHolder.invokeAllResult(msg); resultHolder.invokeAllResult(msg);
// 发送redis消息。 通知位置信息的变化
JSONObject jsonObject = new JSONObject();
jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
jsonObject.put("serial", deviceChannel.getDeviceId());
jsonObject.put("code", deviceChannel.getChannelId());
jsonObject.put("longitude", mobilePosition.getLongitude());
jsonObject.put("latitude", mobilePosition.getLatitude());
jsonObject.put("altitude", mobilePosition.getAltitude());
jsonObject.put("direction", mobilePosition.getDirection());
jsonObject.put("speed", mobilePosition.getSpeed());
redisCatchStorage.sendMobilePositionMsg(jsonObject);
//回复 200 OK //回复 200 OK
try { try {
responseAck(request, Response.OK); responseAck(request, Response.OK);

View File

@ -568,14 +568,14 @@ public class XmlUtil {
String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType"); String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType");
if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){ if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){
try { try {
deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo)); deviceChannel.setPtzType(Integer.parseInt(ptzTypeFromInfo));
}catch (NumberFormatException e){ }catch (NumberFormatException e){
logger.warn("[xml解析] 从通道数据info中获取PTZType失败 {}", ptzTypeFromInfo); logger.warn("[xml解析] 从通道数据info中获取PTZType失败 {}", ptzTypeFromInfo);
} }
} }
} else { } else {
try { try {
deviceChannel.setPTZType(Integer.parseInt(ptzType)); deviceChannel.setPtzType(Integer.parseInt(ptzType));
}catch (NumberFormatException e){ }catch (NumberFormatException e){
logger.warn("[xml解析] 从通道数据中获取PTZType失败 {}", ptzType); logger.warn("[xml解析] 从通道数据中获取PTZType失败 {}", ptzType);
} }

View File

@ -72,9 +72,6 @@ public class ZLMHttpHookListener {
@Autowired @Autowired
private AudioBroadcastManager audioBroadcastManager; private AudioBroadcastManager audioBroadcastManager;
@Autowired
private ZLMServerFactory zlmServerFactory;
@Autowired @Autowired
private IPlayService playService; private IPlayService playService;
@ -123,9 +120,6 @@ public class ZLMHttpHookListener {
@Autowired @Autowired
private VideoStreamSessionManager sessionManager; private VideoStreamSessionManager sessionManager;
@Autowired
private AssistRESTfulUtils assistRESTfulUtils;
@Autowired @Autowired
private SSRCFactory ssrcFactory; private SSRCFactory ssrcFactory;
@ -147,7 +141,7 @@ public class ZLMHttpHookListener {
taskExecutor.execute(() -> { taskExecutor.execute(() -> {
List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive); List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
if (subscribes != null && subscribes.size() > 0) { if (subscribes != null && !subscribes.isEmpty()) {
for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
subscribe.response(null, param); subscribe.response(null, param);
} }
@ -166,7 +160,7 @@ public class ZLMHttpHookListener {
@PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8") @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
public HookResult onPlay(@RequestBody OnPlayHookParam param) { public HookResult onPlay(@RequestBody OnPlayHookParam param) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("[ZLM HOOK] 播放鉴权:{}->{}" + param.getMediaServerId(), param); logger.debug("[ZLM HOOK] 播放鉴权:{}->{}", param.getMediaServerId(), param);
} }
String mediaServerId = param.getMediaServerId(); String mediaServerId = param.getMediaServerId();
@ -252,11 +246,7 @@ public class ZLMHttpHookListener {
taskExecutor.execute(() -> { taskExecutor.execute(() -> {
ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json); ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);
if (subscribe != null) { if (subscribe != null) {
if (mediaInfo != null) {
subscribe.response(mediaInfo, param); subscribe.response(mediaInfo, param);
} else {
new HookResultForOnPublish(1, "zlm not register");
}
} }
}); });
@ -579,9 +569,9 @@ public class ZLMHttpHookListener {
} }
// 收到无人观看说明流也没有在往上级推送 // 收到无人观看说明流也没有在往上级推送
if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) { if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) {
List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId( List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChannelId(
inviteInfo.getChannelId()); inviteInfo.getChannelId());
if (sendRtpItems.size() > 0) { if (!sendRtpItems.isEmpty()) {
for (SendRtpItem sendRtpItem : sendRtpItems) { for (SendRtpItem sendRtpItem : sendRtpItems) {
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
try { try {
@ -798,7 +788,7 @@ public class ZLMHttpHookListener {
logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId()); logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId());
taskExecutor.execute(() -> { taskExecutor.execute(() -> {
List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started); List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);
if (subscribes != null && subscribes.size() > 0) { if (subscribes != null && !subscribes.isEmpty()) {
for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
subscribe.response(null, zlmServerConfig); subscribe.response(null, zlmServerConfig);
} }
@ -847,12 +837,11 @@ public class ZLMHttpHookListener {
*/ */
@ResponseBody @ResponseBody
@PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8") @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8")
public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam public HookResult onRtpServerTimeout(@RequestBody OnRtpServerTimeoutHookParam
param) { param) {
logger.info("[ZLM HOOK] rtpServer收流超时{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc()); logger.info("[ZLM HOOK] rtpServer收流超时{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc());
taskExecutor.execute(() -> { taskExecutor.execute(() -> {
JSONObject json = (JSONObject) JSON.toJSON(param);
List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout);
if (subscribes != null && !subscribes.isEmpty()) { if (subscribes != null && !subscribes.isEmpty()) {
for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {

View File

@ -289,6 +289,10 @@ public class ZLMServerFactory {
* zlm RESTful API stopSendRtp * zlm RESTful API stopSendRtp
*/ */
public Boolean stopSendRtpStream(MediaServerItem mediaServerItem, Map<String, Object>param) { public Boolean stopSendRtpStream(MediaServerItem mediaServerItem, Map<String, Object>param) {
if (mediaServerItem == null) {
logger.error("[停止RTP推流] 失败: 媒体节点为NULL");
return false;
}
Boolean result = false; Boolean result = false;
JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param); JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param);
if (jsonObject == null) { if (jsonObject == null) {

View File

@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.service;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
@ -92,4 +93,9 @@ public interface IDeviceChannelService {
* *
*/ */
void updateChannelStreamIdentification(DeviceChannel channel); void updateChannelStreamIdentification(DeviceChannel channel);
List<DeviceChannel> queryChaneListByDeviceId(String deviceId);
void updateChannelGPS(Device device, DeviceChannel deviceChannel, MobilePosition mobilePosition);
} }

View File

@ -1,5 +1,8 @@
package com.genersoft.iot.vmp.service.bean; package com.genersoft.iot.vmp.service.bean;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.utils.DateUtil;
public class GPSMsgInfo { public class GPSMsgInfo {
/** /**
@ -39,6 +42,18 @@ public class GPSMsgInfo {
private boolean stored; private boolean stored;
public static GPSMsgInfo getInstance(MobilePosition mobilePosition) {
GPSMsgInfo gpsMsgInfo = new GPSMsgInfo();
gpsMsgInfo.setId(mobilePosition.getChannelId());
gpsMsgInfo.setAltitude(mobilePosition.getAltitude() + "");
gpsMsgInfo.setLng(mobilePosition.getLongitude());
gpsMsgInfo.setLat(mobilePosition.getLatitude());
gpsMsgInfo.setSpeed(mobilePosition.getSpeed());
gpsMsgInfo.setDirection(mobilePosition.getDirection() + "");
gpsMsgInfo.setTime(DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
return gpsMsgInfo;
}
public String getId() { public String getId() {
return id; return id;

View File

@ -0,0 +1,49 @@
package com.genersoft.iot.vmp.service.bean;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
public class RequestStopPushStreamMsg {
private SendRtpItem sendRtpItem;
private String platformName;
private int platFormIndex;
public SendRtpItem getSendRtpItem() {
return sendRtpItem;
}
public void setSendRtpItem(SendRtpItem sendRtpItem) {
this.sendRtpItem = sendRtpItem;
}
public String getPlatformName() {
return platformName;
}
public void setPlatformName(String platformName) {
this.platformName = platformName;
}
public int getPlatFormIndex() {
return platFormIndex;
}
public void setPlatFormIndex(int platFormIndex) {
this.platFormIndex = platFormIndex;
}
public static RequestStopPushStreamMsg getInstance(SendRtpItem sendRtpItem, String platformName, int platFormIndex) {
RequestStopPushStreamMsg streamMsg = new RequestStopPushStreamMsg();
streamMsg.setSendRtpItem(sendRtpItem);
streamMsg.setPlatformName(platformName);
streamMsg.setPlatFormIndex(platFormIndex);
return streamMsg;
}
}

View File

@ -6,7 +6,17 @@ package com.genersoft.iot.vmp.service.bean;
public class WvpRedisMsgCmd { public class WvpRedisMsgCmd {
/**
*
*/
public static final String GET_SEND_ITEM = "GetSendItem"; public static final String GET_SEND_ITEM = "GetSendItem";
/**
*
*/
public static final String REQUEST_PUSH_STREAM = "RequestPushStream"; public static final String REQUEST_PUSH_STREAM = "RequestPushStream";
/**
*
*/
public static final String REQUEST_STOP_PUSH_STREAM = "RequestStopPushStream";
} }

View File

@ -1,16 +1,21 @@
package com.genersoft.iot.vmp.service.impl; package com.genersoft.iot.vmp.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.dynamic.datasource.annotation.DS;
import com.genersoft.iot.vmp.common.InviteInfo; import com.genersoft.iot.vmp.common.InviteInfo;
import com.genersoft.iot.vmp.common.InviteSessionType; import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; import com.genersoft.iot.vmp.gb28181.utils.Coordtransform;
import com.genersoft.iot.vmp.service.IDeviceChannelService; import com.genersoft.iot.vmp.service.IDeviceChannelService;
import com.genersoft.iot.vmp.service.IInviteStreamService; import com.genersoft.iot.vmp.service.IInviteStreamService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
import com.genersoft.iot.vmp.storager.dao.DeviceMapper; import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
import com.genersoft.iot.vmp.storager.dao.DeviceMobilePositionMapper;
import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
@ -35,7 +40,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
private final static Logger logger = LoggerFactory.getLogger(DeviceChannelServiceImpl.class); private final static Logger logger = LoggerFactory.getLogger(DeviceChannelServiceImpl.class);
@Autowired @Autowired
private IRedisCatchStorage redisCatchStorage; private EventPublisher eventPublisher;
@Autowired @Autowired
private IInviteStreamService inviteStreamService; private IInviteStreamService inviteStreamService;
@ -46,6 +51,15 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
@Autowired @Autowired
private DeviceMapper deviceMapper; private DeviceMapper deviceMapper;
@Autowired
private DeviceMobilePositionMapper deviceMobilePositionMapper;
@Autowired
private UserSetting userSetting;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Override @Override
public DeviceChannel updateGps(DeviceChannel deviceChannel, Device device) { public DeviceChannel updateGps(DeviceChannel deviceChannel, Device device) {
if (deviceChannel.getLongitude()*deviceChannel.getLatitude() > 0) { if (deviceChannel.getLongitude()*deviceChannel.getLatitude() > 0) {
@ -84,7 +98,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
public void updateChannel(String deviceId, DeviceChannel channel) { public void updateChannel(String deviceId, DeviceChannel channel) {
String channelId = channel.getChannelId(); String channelId = channel.getChannelId();
channel.setDeviceId(deviceId); channel.setDeviceId(deviceId);
// StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
if (inviteInfo != null && inviteInfo.getStreamInfo() != null) { if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
channel.setStreamId(inviteInfo.getStreamInfo().getStream()); channel.setStreamId(inviteInfo.getStreamInfo().getStream());
@ -280,4 +293,64 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
} }
channelMapper.updateChannelStreamIdentification(channel); channelMapper.updateChannelStreamIdentification(channel);
} }
@Override
public List<DeviceChannel> queryChaneListByDeviceId(String deviceId) {
return channelMapper.queryAllChannels(deviceId);
}
@Override
public void updateChannelGPS(Device device, DeviceChannel deviceChannel, MobilePosition mobilePosition) {
if (userSetting.getSavePositionHistory()) {
deviceMobilePositionMapper.insertNewPosition(mobilePosition);
}
if (deviceChannel.getChannelId().equals(deviceChannel.getDeviceId())) {
deviceChannel.setChannelId(null);
}
if (deviceChannel.getGpsTime() == null) {
deviceChannel.setGpsTime(DateUtil.getNow());
}
int updated = channelMapper.updatePosition(deviceChannel);
if (updated == 0) {
return;
}
List<DeviceChannel> deviceChannels = new ArrayList<>();
if (deviceChannel.getChannelId() == null) {
// 有的设备这里上报的deviceId与通道Id是一样这种情况更新设备下的全部通道
List<DeviceChannel> deviceChannelsInDb = queryChaneListByDeviceId(device.getDeviceId());
deviceChannels.addAll(deviceChannelsInDb);
}else {
deviceChannels.add(deviceChannel);
}
if (deviceChannels.isEmpty()) {
return;
}
if (deviceChannels.size() > 100) {
logger.warn("[更新通道位置信息后发送通知] 设备可能是平台,上报的位置信息未标明通道编号," +
"导致所有通道被更新位置, deviceId:{}", device.getDeviceId());
}
for (DeviceChannel channel : deviceChannels) {
// 向关联了该通道并且开启移动位置订阅的上级平台发送移动位置订阅消息
mobilePosition.setChannelId(channel.getChannelId());
try {
eventPublisher.mobilePositionEventPublish(mobilePosition);
}catch (Exception e) {
logger.error("[向上级转发移动位置失败] ", e);
}
// 发送redis消息。 通知位置信息的变化
JSONObject jsonObject = new JSONObject();
jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
jsonObject.put("serial", mobilePosition.getDeviceId());
jsonObject.put("code", mobilePosition.getChannelId());
jsonObject.put("longitude", mobilePosition.getLongitude());
jsonObject.put("latitude", mobilePosition.getLatitude());
jsonObject.put("altitude", mobilePosition.getAltitude());
jsonObject.put("direction", mobilePosition.getDirection());
jsonObject.put("speed", mobilePosition.getSpeed());
redisCatchStorage.sendMobilePositionMsg(jsonObject);
}
}
} }

View File

@ -269,6 +269,8 @@ public class DeviceServiceImpl implements IDeviceService {
int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForCatalog(),30); int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForCatalog(),30);
// 设置最小值为30 // 设置最小值为30
dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, (subscribeCycleForCatalog -1) * 1000); dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, (subscribeCycleForCatalog -1) * 1000);
catalogSubscribeTask.run();
return true; return true;
} }
@ -302,6 +304,7 @@ public class DeviceServiceImpl implements IDeviceService {
int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForMobilePosition(),30); int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForMobilePosition(),30);
// 刷新订阅 // 刷新订阅
dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog * 1000); dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog * 1000);
mobilePositionSubscribeTask.run();
return true; return true;
} }

View File

@ -1409,6 +1409,14 @@ public class PlayServiceImpl implements IPlayService {
logger.info("调用ZLM推流接口, 结果: {}", jsonObject); logger.info("调用ZLM推流接口, 结果: {}", jsonObject);
logger.info("RTP推流成功[ {}/{} ]{}->{}, ", param.get("app"), param.get("stream"), jsonObject.getString("local_port"), logger.info("RTP推流成功[ {}/{} ]{}->{}, ", param.get("app"), param.get("stream"), jsonObject.getString("local_port"),
sendRtpItem.isTcpActive()?"被动发流": param.get("dst_url") + ":" + param.get("dst_port")); sendRtpItem.isTcpActive()?"被动发流": param.get("dst_url") + ":" + param.get("dst_port"));
if (sendRtpItem.getPlayType() == InviteStreamType.PUSH && correlationInfo instanceof ParentPlatform) {
ParentPlatform platform = (ParentPlatform)correlationInfo;
MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, sendRtpItem.getApp(), sendRtpItem.getStream(),
sendRtpItem.getChannelId(), platform.getServerGBId(), platform.getName(), userSetting.getServerId(),
sendRtpItem.getMediaServerId());
messageForPushChannel.setPlatFormIndex(platform.getId());
redisCatchStorage.sendPlatformStartPlayMsg(messageForPushChannel);
}
} else { } else {
logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSONObject.toJSONString(param)); logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSONObject.toJSONString(param));
if (sendRtpItem.isOnlyAudio()) { if (sendRtpItem.isOnlyAudio()) {

View File

@ -133,7 +133,10 @@ public class RedisGbPlayMsgListener implements MessageListener {
case WvpRedisMsgCmd.REQUEST_PUSH_STREAM: case WvpRedisMsgCmd.REQUEST_PUSH_STREAM:
RequestPushStreamMsg param = JSON.to(RequestPushStreamMsg.class, wvpRedisMsg.getContent()); RequestPushStreamMsg param = JSON.to(RequestPushStreamMsg.class, wvpRedisMsg.getContent());
requestPushStreamMsgHand(param, wvpRedisMsg.getFromId(), wvpRedisMsg.getSerial()); requestPushStreamMsgHand(param, wvpRedisMsg.getFromId(), wvpRedisMsg.getSerial());
break;
case WvpRedisMsgCmd.REQUEST_STOP_PUSH_STREAM:
RequestStopPushStreamMsg streamMsg = JSON.to(RequestStopPushStreamMsg.class, wvpRedisMsg.getContent());
requestStopPushStreamMsgHand(streamMsg, wvpRedisMsg.getFromId(), wvpRedisMsg.getSerial());
break; break;
default: default:
break; break;
@ -397,6 +400,19 @@ public class RedisGbPlayMsgListener implements MessageListener {
redisTemplate.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject); redisTemplate.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject);
} }
/**
*
*/
public void sendMsgForStopSendRtpStream(String serverId, RequestStopPushStreamMsg streamMsg) {
String key = UUID.randomUUID().toString();
WvpRedisMsg redisMsg = WvpRedisMsg.getRequestInstance(userSetting.getServerId(), serverId,
WvpRedisMsgCmd.REQUEST_STOP_PUSH_STREAM, key, JSON.toJSONString(streamMsg));
JSONObject jsonObject = (JSONObject)JSON.toJSON(redisMsg);
logger.info("[REDIS 请求其他平台停止推流] {}: {}", serverId, jsonObject);
redisTemplate.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject);
}
private SendRtpItem querySendRTPServer(String platformGbId, String channelId, String streamId, String callId) { private SendRtpItem querySendRTPServer(String platformGbId, String channelId, String streamId, String callId) {
if (platformGbId == null) { if (platformGbId == null) {
platformGbId = "*"; platformGbId = "*";
@ -423,4 +439,36 @@ public class RedisGbPlayMsgListener implements MessageListener {
return null; return null;
} }
} }
/**
*
*/
private void requestStopPushStreamMsgHand(RequestStopPushStreamMsg streamMsg, String fromId, String serial) {
SendRtpItem sendRtpItem = streamMsg.getSendRtpItem();
if (sendRtpItem == null) {
logger.info("[REDIS 执行其他平台的请求停止推流] 失败: sendRtpItem为NULL");
return;
}
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
if (mediaInfo == null) {
// TODO 回复错误
return;
}
Map<String, Object> param = new HashMap<>();
param.put("vhost","__defaultVhost__");
param.put("app",sendRtpItem.getApp());
param.put("stream",sendRtpItem.getStream());
param.put("ssrc", sendRtpItem.getSsrc());
if (zlmServerFactory.stopSendRtpStream(mediaInfo, param)) {
logger.info("[REDIS 执行其他平台的请求停止推流] 成功: {}/{}", sendRtpItem.getApp(), sendRtpItem.getStream());
// 发送redis消息
MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(),
sendRtpItem.getPlatformId(), streamMsg.getPlatformName(), userSetting.getServerId(), sendRtpItem.getMediaServerId());
messageForPushChannel.setPlatFormIndex(streamMsg.getPlatFormIndex());
redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel);
}
}
} }

View File

@ -73,7 +73,7 @@ public class RedisPushStreamCloseResponseListener implements MessageListener {
MessageForPushChannel pushChannel = JSON.parseObject(message.getBody(), MessageForPushChannel.class); MessageForPushChannel pushChannel = JSON.parseObject(message.getBody(), MessageForPushChannel.class);
StreamPushItem push = streamPushService.getPush(pushChannel.getApp(), pushChannel.getStream()); StreamPushItem push = streamPushService.getPush(pushChannel.getApp(), pushChannel.getStream());
if (push != null) { if (push != null) {
List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId( List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChannelId(
push.getGbId()); push.getGbId());
if (!sendRtpItems.isEmpty()) { if (!sendRtpItems.isEmpty()) {
for (SendRtpItem sendRtpItem : sendRtpItems) { for (SendRtpItem sendRtpItem : sendRtpItems) {

View File

@ -88,7 +88,8 @@ public class RedisPushStreamStatusListMsgListener implements MessageListener {
streamPushItemForSave.add(streamPushItem); streamPushItemForSave.add(streamPushItem);
allGBId.put(streamPushItem.getGbId(), streamPushItem); allGBId.put(streamPushItem.getGbId(), streamPushItem);
} else { } else {
if (allGBId.containsKey(streamPushItem.getGbId())) { if (allGBId.containsKey(streamPushItem.getGbId())
&& (!allGBId.get(streamPushItem.getGbId()).getApp().equals(streamPushItem.getApp()) || !allGBId.get(streamPushItem.getGbId()).getStream().equals(streamPushItem.getStream()))) {
GbStream gbStream = allGBId.get(streamPushItem.getGbId()); GbStream gbStream = allGBId.get(streamPushItem.getGbId());
logger.warn("[REDIS消息-推流设备列表更新-UPDATE] 国标编号重复: {}, 已分配给{}/{}", logger.warn("[REDIS消息-推流设备列表更新-UPDATE] 国标编号重复: {}, 已分配给{}/{}",
streamPushItem.getGbId(), gbStream.getApp(), gbStream.getStream()); streamPushItem.getGbId(), gbStream.getApp(), gbStream.getStream());

View File

@ -181,7 +181,7 @@ public interface IRedisCatchStorage {
*/ */
void sendStreamPushRequestedMsgForStatus(); void sendStreamPushRequestedMsgForStatus();
List<SendRtpItem> querySendRTPServerByChnnelId(String channelId); List<SendRtpItem> querySendRTPServerByChannelId(String channelId);
List<SendRtpItem> querySendRTPServerByStream(String stream); List<SendRtpItem> querySendRTPServerByStream(String stream);

View File

@ -23,7 +23,7 @@ public interface DeviceChannelMapper {
"longitude_wgs84, latitude_wgs84, has_audio, create_time, update_time, business_group_id, gps_time, stream_identification) " + "longitude_wgs84, latitude_wgs84, has_audio, create_time, update_time, business_group_id, gps_time, stream_identification) " +
"VALUES (#{channelId}, #{deviceId}, #{name}, #{manufacture}, #{model}, #{owner}, #{civilCode}, #{block}," + "VALUES (#{channelId}, #{deviceId}, #{name}, #{manufacture}, #{model}, #{owner}, #{civilCode}, #{block}," +
"#{address}, #{parental}, #{parentId}, #{safetyWay}, #{registerWay}, #{certNum}, #{certifiable}, #{errCode}, #{secrecy}, " + "#{address}, #{parental}, #{parentId}, #{safetyWay}, #{registerWay}, #{certNum}, #{certifiable}, #{errCode}, #{secrecy}, " +
"#{ipAddress}, #{port}, #{password}, #{PTZType}, #{status}, #{streamId}, #{longitude}, #{latitude}, #{longitudeGcj02}, " + "#{ipAddress}, #{port}, #{password}, #{ptzType}, #{status}, #{streamId}, #{longitude}, #{latitude}, #{longitudeGcj02}, " +
"#{latitudeGcj02}, #{longitudeWgs84}, #{latitudeWgs84}, #{hasAudio}, #{createTime}, #{updateTime}, #{businessGroupId}, #{gpsTime}, #{streamIdentification})") "#{latitudeGcj02}, #{longitudeWgs84}, #{latitudeWgs84}, #{hasAudio}, #{createTime}, #{updateTime}, #{businessGroupId}, #{gpsTime}, #{streamIdentification})")
int add(DeviceChannel channel); int add(DeviceChannel channel);
@ -48,7 +48,7 @@ public interface DeviceChannelMapper {
"<if test='ipAddress != null'>, ip_address=#{ipAddress}</if>" + "<if test='ipAddress != null'>, ip_address=#{ipAddress}</if>" +
"<if test='port != null'>, port=#{port}</if>" + "<if test='port != null'>, port=#{port}</if>" +
"<if test='password != null'>, password=#{password}</if>" + "<if test='password != null'>, password=#{password}</if>" +
"<if test='PTZType != null'>, custom_ptz_type=#{PTZType}</if>" + "<if test='ptzType != null'>, custom_ptz_type=#{ptzType}</if>" +
"<if test='status != null'>, status=#{status}</if>" + "<if test='status != null'>, status=#{status}</if>" +
"<if test='streamId != null'>, stream_id=#{streamId}</if>" + "<if test='streamId != null'>, stream_id=#{streamId}</if>" +
"<if test='hasAudio != null'>, has_audio=#{hasAudio}</if>" + "<if test='hasAudio != null'>, has_audio=#{hasAudio}</if>" +
@ -250,7 +250,7 @@ public interface DeviceChannelMapper {
"#{item.owner}, #{item.civilCode}, #{item.block},#{item.subCount}," + "#{item.owner}, #{item.civilCode}, #{item.block},#{item.subCount}," +
"#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, " + "#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, " +
"#{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.secrecy}, " + "#{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.secrecy}, " +
"#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " + "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.ptzType}, #{item.status}, " +
"#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " + "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " +
"#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " + "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " +
"#{item.businessGroupId}, #{item.gpsTime}, #{item.streamIdentification}) " + "#{item.businessGroupId}, #{item.gpsTime}, #{item.streamIdentification}) " +
@ -271,7 +271,7 @@ public interface DeviceChannelMapper {
"#{item.owner}, #{item.civilCode}, #{item.block},#{item.subCount}," + "#{item.owner}, #{item.civilCode}, #{item.block},#{item.subCount}," +
"#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, " + "#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, " +
"#{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.secrecy}, " + "#{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.secrecy}, " +
"#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " + "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.ptzType}, #{item.status}, " +
"#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " + "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " +
"#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " + "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " +
"#{item.businessGroupId}, #{item.gpsTime}) " + "#{item.businessGroupId}, #{item.gpsTime}) " +
@ -339,7 +339,7 @@ public interface DeviceChannelMapper {
"<if test='item.ipAddress != null'>, ip_address=#{item.ipAddress}</if>" + "<if test='item.ipAddress != null'>, ip_address=#{item.ipAddress}</if>" +
"<if test='item.port != null'>, port=#{item.port}</if>" + "<if test='item.port != null'>, port=#{item.port}</if>" +
"<if test='item.password != null'>, password=#{item.password}</if>" + "<if test='item.password != null'>, password=#{item.password}</if>" +
"<if test='item.PTZType != null'>, ptz_type=#{item.PTZType}</if>" + "<if test='item.ptzType != null'>, ptz_type=#{item.ptzType}</if>" +
"<if test='item.status != null'>, status=#{item.status}</if>" + "<if test='item.status != null'>, status=#{item.status}</if>" +
"<if test='item.streamId != null'>, stream_id=#{item.streamId}</if>" + "<if test='item.streamId != null'>, stream_id=#{item.streamId}</if>" +
"<if test='item.hasAudio != null'>, has_audio=#{item.hasAudio}</if>" + "<if test='item.hasAudio != null'>, has_audio=#{item.hasAudio}</if>" +
@ -395,7 +395,7 @@ public interface DeviceChannelMapper {
"WHERE device_id=#{deviceId} " + "WHERE device_id=#{deviceId} " +
" <if test='channelId != null' > AND channel_id=#{channelId}</if>" + " <if test='channelId != null' > AND channel_id=#{channelId}</if>" +
" </script>"}) " </script>"})
void updatePosition(DeviceChannel deviceChannel); int updatePosition(DeviceChannel deviceChannel);
@Select("SELECT * FROM wvp_device_channel WHERE length(trim(stream_id)) > 0") @Select("SELECT * FROM wvp_device_channel WHERE length(trim(stream_id)) > 0")
List<DeviceChannel> getAllChannelInPlay(); List<DeviceChannel> getAllChannelInPlay();

View File

@ -269,7 +269,7 @@ public interface DeviceMapper {
"charset,"+ "charset,"+
"ssrc_check,"+ "ssrc_check,"+
"as_message_channel,"+ "as_message_channel,"+
"broadcastPushAfterAck,"+ "broadcast_push_after_ack,"+
"geo_coord_sys,"+ "geo_coord_sys,"+
"on_line,"+ "on_line,"+
"media_server_id"+ "media_server_id"+

View File

@ -184,7 +184,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
} }
@Override @Override
public List<SendRtpItem> querySendRTPServerByChnnelId(String channelId) { public List<SendRtpItem> querySendRTPServerByChannelId(String channelId) {
if (channelId == null) { if (channelId == null) {
return null; return null;
} }

View File

@ -13,7 +13,7 @@ import com.genersoft.iot.vmp.conf.security.JwtUtils;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@ -45,7 +45,7 @@ public class DeviceControl {
private IVideoManagerStorage storager; private IVideoManagerStorage storager;
@Autowired @Autowired
private SIPCommander cmder; private ISIPCommander cmder;
@Autowired @Autowired
private DeferredResultHolder resultHolder; private DeferredResultHolder resultHolder;
@ -254,15 +254,13 @@ public class DeviceControl {
@Operation(summary = "看守位控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Operation(summary = "看守位控制", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "enabled", description = "是否开启看守位 1:开启,0:关闭", required = true) @Parameter(name = "enabled", description = "是否开启看守位", required = true)
@Parameter(name = "presetIndex", description = "调用预置位编号") @Parameter(name = "presetIndex", description = "调用预置位编号")
@Parameter(name = "resetTime", description = "自动归位时间间隔") @Parameter(name = "resetTime", description = "自动归位时间间隔 单位:秒")
@GetMapping("/home_position/{deviceId}/{enabled}") @GetMapping("/home_position")
public DeferredResult<String> homePositionApi(@PathVariable String deviceId, public DeferredResult<String> homePositionApi(String deviceId, String channelId, Boolean enabled,
@PathVariable String enabled, @RequestParam(required = false) Integer resetTime,
@RequestParam(required = false) String resetTime, @RequestParam(required = false) Integer presetIndex) {
@RequestParam(required = false) String presetIndex,
String channelId) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("报警复位API调用"); logger.debug("报警复位API调用");
} }

View File

@ -114,5 +114,5 @@ user-settings:
device-status-notify: true device-status-notify: true
# [可选] 日志配置, 一般不需要改 # [可选] 日志配置, 一般不需要改
logging: logging:
config: classpath:logback-spring-local.xml config: classpath:logback-spring.xml

View File

@ -100,9 +100,9 @@
<span v-show="!scope.row.edit">{{ scope.row.location }}</span> <span v-show="!scope.row.edit">{{ scope.row.location }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="ptztype" label="云台类型" min-width="100"> <el-table-column prop="ptzType" label="云台类型" min-width="100">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-select v-show="scope.row.edit" v-model="scope.row.ptztype" <el-select v-show="scope.row.edit" v-model="scope.row.ptzType"
placeholder="云台类型" filterable> placeholder="云台类型" filterable>
<el-option <el-option
v-for="(value, key) in ptzTypes" v-for="(value, key) in ptzTypes"
@ -111,7 +111,7 @@
:value="key" :value="key"
/> />
</el-select> </el-select>
<div v-show="!scope.row.edit">{{ scope.row.ptztypeText }}</div> <div v-show="!scope.row.edit">{{ scope.row.ptzTypeText }}</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="开启音频" min-width="100"> <el-table-column label="开启音频" min-width="100">
@ -178,13 +178,24 @@
@click="changeSubchannel(scope.row)">查看 @click="changeSubchannel(scope.row)">查看
</el-button> </el-button>
<el-divider v-if="scope.row.subCount > 0 || scope.row.parental === 1" direction="vertical"></el-divider> <el-divider v-if="scope.row.subCount > 0 || scope.row.parental === 1" direction="vertical"></el-divider>
<el-button size="medium" v-bind:disabled="device == null || device.online === 0" <!-- <el-button size="medium" v-bind:disabled="device == null || device.online === 0"-->
icon="el-icon-video-camera" <!-- icon="el-icon-video-camera"-->
type="text" @click="queryRecords(scope.row)">设备录像 <!-- type="text" @click="queryRecords(scope.row)">设备录像-->
</el-button> <!-- </el-button>-->
<el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-cloudy" <!-- <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-cloudy"-->
type="text" @click="queryCloudRecords(scope.row)">云端录像 <!-- type="text" @click="queryCloudRecords(scope.row)">云端录像-->
<!-- </el-button>-->
<el-dropdown @command="(command)=>{moreClick(command, scope.row)}">
<el-button size="medium" type="text" >
更多功能<i class="el-icon-arrow-down el-icon--right"></i>
</el-button> </el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="records" v-bind:disabled="device == null || device.online === 0">
设备录像</el-dropdown-item>
<el-dropdown-item command="cloudRecords" v-bind:disabled="device == null || device.online === 0" >
云端录像</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -312,7 +323,7 @@ export default {
that.total = res.data.data.total; that.total = res.data.data.total;
that.deviceChannelList = res.data.data.list; that.deviceChannelList = res.data.data.list;
that.deviceChannelList.forEach(e => { that.deviceChannelList.forEach(e => {
e.ptztype = e.ptztype + ""; e.ptzType = e.ptzType + "";
that.$set(e, "edit", false); that.$set(e, "edit", false);
that.$set(e, "location", ""); that.$set(e, "location", "");
if (e.longitude && e.latitude) { if (e.longitude && e.latitude) {
@ -372,6 +383,13 @@ export default {
// that.$message.error(""); // that.$message.error("");
}); });
}, },
moreClick: function (command, itemData) {
if (command === "records") {
this.queryRecords(itemData)
}else if (command === "cloudRecords") {
this.queryCloudRecords(itemData)
}
},
queryRecords: function (itemData) { queryRecords: function (itemData) {
let deviceId = this.deviceId; let deviceId = this.deviceId;
let channelId = itemData.channelId; let channelId = itemData.channelId;
@ -460,7 +478,7 @@ export default {
this.total = res.data.data.total; this.total = res.data.data.total;
this.deviceChannelList = res.data.data.list; this.deviceChannelList = res.data.data.list;
this.deviceChannelList.forEach(e => { this.deviceChannelList.forEach(e => {
e.ptztype = e.ptztype + ""; e.ptzType = e.ptzType + "";
this.$set(e, "edit", false); this.$set(e, "edit", false);
this.$set(e, "location", ""); this.$set(e, "location", "");
if (e.longitude && e.latitude) { if (e.longitude && e.latitude) {

View File

@ -131,11 +131,11 @@ export default {
type = 2; type = 2;
} }
console.log(type) console.log(type)
if (item.basicData.ptztype === 1 ) { // 1-;2-;3-;4- if (item.basicData.ptzType === 1 ) { // 1-;2-;3-;4-
type = 4; type = 4;
}else if (item.basicData.ptztype === 2) { }else if (item.basicData.ptzType === 2) {
type = 5; type = 5;
}else if (item.basicData.ptztype === 3 || item.basicData.ptztype === 4) { }else if (item.basicData.ptzType === 3 || item.basicData.ptzType === 4) {
type = 6; type = 6;
} }
}else { }else {

View File

@ -7,7 +7,7 @@
<el-descriptions-item label="设备归属" >{{channel.owner}}</el-descriptions-item> <el-descriptions-item label="设备归属" >{{channel.owner}}</el-descriptions-item>
<el-descriptions-item label="行政区域" >{{channel.civilCode}}</el-descriptions-item> <el-descriptions-item label="行政区域" >{{channel.civilCode}}</el-descriptions-item>
<el-descriptions-item label="安装地址" >{{channel.address}}</el-descriptions-item> <el-descriptions-item label="安装地址" >{{channel.address}}</el-descriptions-item>
<el-descriptions-item label="云台类型" >{{channel.ptztypeText}}</el-descriptions-item> <el-descriptions-item label="云台类型" >{{channel.ptzTypeText}}</el-descriptions-item>
<el-descriptions-item label="经纬度" >{{channel.longitude}},{{channel.latitude}}</el-descriptions-item> <el-descriptions-item label="经纬度" >{{channel.longitude}},{{channel.latitude}}</el-descriptions-item>
<el-descriptions-item label="状态"> <el-descriptions-item label="状态">
<el-tag size="small" v-if="channel.status === 1">线</el-tag> <el-tag size="small" v-if="channel.status === 1">线</el-tag>

View File

@ -41,8 +41,8 @@ export default {
zlmsdpUrl: url,// zlmsdpUrl: url,//
simulecast: false, simulecast: false,
useCamera: false, useCamera: false,
audioEnable: false, audioEnable: true,
videoEnable: false, videoEnable: true,
recvOnly: true, recvOnly: true,
}) })
webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,(e)=>{// ICE webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,(e)=>{// ICE

View File

@ -243,7 +243,7 @@ export default {
}, },
getImageByChannel: function (channel) { getImageByChannel: function (channel) {
let src = "static/images/gis/camera.png" let src = "static/images/gis/camera.png"
switch (channel.ptztype) { switch (channel.ptzType) {
case 1: case 1:
if (channel.status === 1) { if (channel.status === 1) {
src = "static/images/gis/camera1.png" src = "static/images/gis/camera1.png"