修复国标级联录像回放控制

pull/1642/head
648540858 2024-09-24 11:00:42 +08:00
parent f7936117f9
commit 1a890b5e17
6 changed files with 82 additions and 72 deletions

View File

@ -350,7 +350,9 @@ public interface ISIPCommander {
void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException; void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException;
/** void playbackControlCmd(Device device, DeviceChannel channel, String stream, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException;
/**
* NOTIFY * NOTIFY
* @param device * @param device
* @param deviceAlarm * @param deviceAlarm

View File

@ -94,7 +94,7 @@ public class SIPRequestHeaderPlarformProvider {
if (www == null) { if (www == null) {
AuthorizationHeader authorizationHeader = SipFactory.getInstance().createHeaderFactory().createAuthorizationHeader("Digest"); AuthorizationHeader authorizationHeader = SipFactory.getInstance().createHeaderFactory().createAuthorizationHeader("Digest");
String username = parentPlatform.getUsername(); String username = parentPlatform.getUsername();
if ( username == null || username == "" ) if ( username == null || username.isEmpty())
{ {
authorizationHeader.setUsername(parentPlatform.getDeviceGBId()); authorizationHeader.setUsername(parentPlatform.getDeviceGBId());
} else { } else {

View File

@ -1363,15 +1363,21 @@ public class SIPCommander implements ISIPCommander {
@Override @Override
public void playbackControlCmd(Device device, DeviceChannel channel, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException { public void playbackControlCmd(Device device, DeviceChannel channel, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException {
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(streamInfo.getStream()); playbackControlCmd(device, channel, streamInfo.getStream(), content, errorEvent, okEvent);
}
@Override
public void playbackControlCmd(Device device, DeviceChannel channel, String stream, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException {
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(stream);
if (ssrcTransaction == null) { if (ssrcTransaction == null) {
log.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); log.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), stream);
return; return;
} }
SIPRequest request = headerProvider.createInfoRequest(device, channel.getDeviceId(), content, ssrcTransaction.getSipTransactionInfo()); SIPRequest request = headerProvider.createInfoRequest(device, channel.getDeviceId(), content, ssrcTransaction.getSipTransactionInfo());
if (request == null) { if (request == null) {
log.info("[回放控制]构建Request信息失败设备{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream()); log.info("[回放控制]构建Request信息失败设备{}, 流ID: {}", device.getDeviceId(), stream);
return; return;
} }

View File

@ -178,6 +178,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
} }
}else { }else {
// 点播成功, TODO 可以在此处检测cancel命令是否存在存在则不发送 // 点播成功, TODO 可以在此处检测cancel命令是否存在存在则不发送
// 构建sendRTP内容 // 构建sendRTP内容
SendRtpInfo sendRtpItem = sendRtpServerService.createSendRtpInfo(streamInfo.getMediaServer(), SendRtpInfo sendRtpItem = sendRtpServerService.createSendRtpInfo(streamInfo.getMediaServer(),
inviteInfo.getIp(), inviteInfo.getPort(), inviteInfo.getSsrc(), platform.getServerGBId(), inviteInfo.getIp(), inviteInfo.getPort(), inviteInfo.getSsrc(), platform.getServerGBId(),

View File

@ -1,13 +1,8 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info; package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info;
import com.genersoft.iot.vmp.common.InviteInfo;
import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; import com.genersoft.iot.vmp.gb28181.service.*;
import com.genersoft.iot.vmp.gb28181.service.IDeviceService;
import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService;
import com.genersoft.iot.vmp.gb28181.service.IPlatformService;
import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager; import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
@ -56,6 +51,9 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I
@Autowired @Autowired
private IDeviceService deviceService; private IDeviceService deviceService;
@Autowired
private IGbChannelService channelService;
@Autowired @Autowired
private IDeviceChannelService deviceChannelService; private IDeviceChannelService deviceChannelService;
@ -76,73 +74,73 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I
@Override @Override
public void process(RequestEvent evt) { public void process(RequestEvent evt) {
log.debug("接收到消息:" + evt.getRequest());
SIPRequest request = (SIPRequest) evt.getRequest(); SIPRequest request = (SIPRequest) evt.getRequest();
CallIdHeader callIdHeader = request.getCallIdHeader(); CallIdHeader callIdHeader = request.getCallIdHeader();
// 先从会话内查找 // 先从会话内查找
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByCallId(callIdHeader.getCallId());
// 查询设备是否存在
Device device = redisCatchStorage.getDevice(ssrcTransaction.getDeviceId());
// 查询上级平台是否存在
Platform parentPlatform = platformService.queryPlatformByServerGBId(ssrcTransaction.getDeviceId());
try { try {
if (device != null && parentPlatform != null) { SendRtpInfo sendRtpInfo = sendRtpServerService.queryByCallId(callIdHeader.getCallId());
log.warn("[重复]平台与设备编号重复:{}", ssrcTransaction.getDeviceId()); if (sendRtpInfo == null || !sendRtpInfo.isSendToPlatform()) {
String hostAddress = request.getRemoteAddress().getHostAddress();
int remotePort = request.getRemotePort();
if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) {
parentPlatform = null;
}else {
device = null;
}
}
if (device == null && parentPlatform == null) {
// 不存在则回复404 // 不存在则回复404
responseAck(request, Response.NOT_FOUND, "device "+ ssrcTransaction.getDeviceId() +" not found"); log.warn("[INFO 消息] 事务未找到, callID {}", callIdHeader.getCallId());
log.warn("[设备未找到 ] {}", ssrcTransaction.getDeviceId()); responseAck(request, Response.NOT_FOUND, "transaction not found");
if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){ return;
DeviceNotFoundEvent deviceNotFoundEvent = new DeviceNotFoundEvent(evt.getDialog()); }
deviceNotFoundEvent.setCallId(callIdHeader.getCallId()); // 查询上级平台是否存在
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent); Platform platform = platformService.queryPlatformByServerGBId(sendRtpInfo.getTargetId());
sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult); if (platform == null || !platform.isStatus()) {
}; // 不存在则回复404
}else { log.warn("[INFO 消息] 平台未找到或者已离线: 平台: {}", sendRtpInfo.getTargetId());
ContentTypeHeader header = (ContentTypeHeader)evt.getRequest().getHeader(ContentTypeHeader.NAME); responseAck(request, Response.NOT_FOUND, "platform "+ sendRtpInfo.getTargetId() +" not found or offline");
String contentType = header.getContentType(); return;
String contentSubType = header.getContentSubType(); }
if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) { CommonGBChannel channel = channelService.getOne(sendRtpInfo.getChannelId());
SendRtpInfo sendRtpItem = sendRtpServerService.queryByCallId(callIdHeader.getCallId()); if (channel == null) {
String streamId = sendRtpItem.getStream(); // 不存在则回复404
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId); log.warn("[INFO 消息] 通道不存在: 通道ID {}", sendRtpInfo.getChannelId());
if (null == inviteInfo) { responseAck(request, Response.NOT_FOUND, "channel not found or offline");
responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found"); return;
return; }
} // 判断通道类型
Device device1 = deviceService.getDeviceByDeviceId(inviteInfo.getDeviceId()); if (channel.getGbDeviceId() == null) {
DeviceChannel deviceChannel = deviceChannelService.getOneById(inviteInfo.getChannelId()); // 非国标通道不支持录像回放控制
if (device1 != null && deviceChannel != null && inviteInfo.getStreamInfo() != null) { log.warn("[INFO 消息] 非国标通道不支持录像回放控制: 通道ID {}", sendRtpInfo.getChannelId());
// 不解析协议, 直接转发给对应的设备 responseAck(request, Response.FORBIDDEN, "");
cmder.playbackControlCmd(device1, deviceChannel, inviteInfo.getStreamInfo(),new String(evt.getRequest().getRawContent()), eventResult -> { return;
// 失败的回复 }
try {
responseAck(request, eventResult.statusCode, eventResult.msg);
} catch (SipException | InvalidArgumentException | ParseException e) {
log.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
}
}, eventResult -> {
// 成功的回复
try {
responseAck(request, eventResult.statusCode);
} catch (SipException | InvalidArgumentException | ParseException e) {
log.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
}
});
}else {
responseAck(request, Response.NOT_FOUND, "not found");
}
} // 根据通道ID获取所属设备
Device device = deviceService.getDeviceByChannelId(sendRtpInfo.getChannelId());
if (device == null) {
// 不存在则回复404
log.warn("[INFO 消息] 通道所属设备不存在, 通道ID {}", sendRtpInfo.getChannelId());
responseAck(request, Response.NOT_FOUND, "platform "+ sendRtpInfo.getChannelId() +" not found or offline");
return;
}
// 获取通道的原始信息
DeviceChannel deviceChannel = deviceChannelService.getOneById(sendRtpInfo.getChannelId());
// 向原始通道转发控制消息
ContentTypeHeader header = (ContentTypeHeader)evt.getRequest().getHeader(ContentTypeHeader.NAME);
String contentType = header.getContentType();
String contentSubType = header.getContentSubType();
if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) {
log.info("[INFO 消息] 平台: {}->{}({})/{}", platform.getServerGBId(), device.getName(),
device.getDeviceId(), deviceChannel.getId());
// 不解析协议, 直接转发给对应的设备
cmder.playbackControlCmd(device, deviceChannel, sendRtpInfo.getStream(), new String(evt.getRequest().getRawContent()), eventResult -> {
// 失败的回复
try {
responseAck(request, eventResult.statusCode, eventResult.msg);
} catch (SipException | InvalidArgumentException | ParseException e) {
log.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
}
}, eventResult -> {
// 成功的回复
try {
responseAck(request, eventResult.statusCode);
} catch (SipException | InvalidArgumentException | ParseException e) {
log.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
}
});
} }
} catch (SipException e) { } catch (SipException e) {
log.warn("SIP 回复错误", e); log.warn("SIP 回复错误", e);

View File

@ -706,6 +706,9 @@ public class XmlUtil {
* @return * @return
*/ */
private static Object simpleTypeDeal(Class<?> tClass, Object val) { private static Object simpleTypeDeal(Class<?> tClass, Object val) {
if (val == null || val.toString().equalsIgnoreCase("null")) {
return null;
}
if (tClass.equals(String.class)) { if (tClass.equals(String.class)) {
return val.toString(); return val.toString();
} }