国标级联推送推流 支持多wvp间自动选择与推送
This commit is contained in:
parent
c827d1518b
commit
e0344ccf97
@ -1,12 +1,4 @@
|
|||||||
alter table parent_platform
|
alter table stream_push
|
||||||
add startOfflinePush int default 0 null;
|
add serverId varchar(50) not null;
|
||||||
|
|
||||||
alter table parent_platform
|
|
||||||
add administrativeDivision varchar(50) not null;
|
|
||||||
|
|
||||||
alter table parent_platform
|
|
||||||
add catalogGroup int default 1 null;
|
|
||||||
|
|
||||||
alter table device
|
|
||||||
add ssrcCheck int default 0 null;
|
|
||||||
|
|
||||||
|
@ -97,4 +97,5 @@ public class VideoManagerConstants {
|
|||||||
//************************** 第三方 ****************************************
|
//************************** 第三方 ****************************************
|
||||||
public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
|
public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
|
||||||
public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_";
|
public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@ package com.genersoft.iot.vmp.conf;
|
|||||||
|
|
||||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||||
import com.genersoft.iot.vmp.service.impl.RedisAlarmMsgListener;
|
import com.genersoft.iot.vmp.service.impl.RedisAlarmMsgListener;
|
||||||
import com.genersoft.iot.vmp.service.impl.RedisGPSMsgListener;
|
import com.genersoft.iot.vmp.service.impl.RedisGpsMsgListener;
|
||||||
|
import com.genersoft.iot.vmp.service.impl.RedisGbPlayMsgListener;
|
||||||
|
import com.genersoft.iot.vmp.service.impl.RedisStreamMsgListener;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -47,11 +49,17 @@ public class RedisConfig extends CachingConfigurerSupport {
|
|||||||
private int poolMaxWait;
|
private int poolMaxWait;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisGPSMsgListener redisGPSMsgListener;
|
private RedisGpsMsgListener redisGPSMsgListener;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisAlarmMsgListener redisAlarmMsgListener;
|
private RedisAlarmMsgListener redisAlarmMsgListener;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisStreamMsgListener redisStreamMsgListener;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisGbPlayMsgListener redisGbPlayMsgListener;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public JedisPool jedisPool() {
|
public JedisPool jedisPool() {
|
||||||
if (StringUtils.isBlank(password)) {
|
if (StringUtils.isBlank(password)) {
|
||||||
@ -98,6 +106,8 @@ public class RedisConfig extends CachingConfigurerSupport {
|
|||||||
container.setConnectionFactory(connectionFactory);
|
container.setConnectionFactory(connectionFactory);
|
||||||
container.addMessageListener(redisGPSMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_GPS));
|
container.addMessageListener(redisGPSMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_GPS));
|
||||||
container.addMessageListener(redisAlarmMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM_RECEIVE));
|
container.addMessageListener(redisAlarmMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM_RECEIVE));
|
||||||
|
container.addMessageListener(redisStreamMsgListener, new PatternTopic(VideoManagerConstants.WVP_MSG_STREAM_CHANGE_PREFIX + "PUSH"));
|
||||||
|
container.addMessageListener(redisGbPlayMsgListener, new PatternTopic(RedisGbPlayMsgListener.WVP_PUSH_STREAM_KEY));
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +71,11 @@ public class SendRtpItem {
|
|||||||
*/
|
*/
|
||||||
private String mediaServerId;
|
private String mediaServerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用的服务的ID
|
||||||
|
*/
|
||||||
|
private String serverId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* invite的callId
|
* invite的callId
|
||||||
*/
|
*/
|
||||||
@ -259,4 +264,12 @@ public class SendRtpItem {
|
|||||||
public void setOnlyAudio(boolean onlyAudio) {
|
public void setOnlyAudio(boolean onlyAudio) {
|
||||||
this.onlyAudio = onlyAudio;
|
this.onlyAudio = onlyAudio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getServerId() {
|
||||||
|
return serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerId(String serverId) {
|
||||||
|
this.serverId = serverId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,9 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask {
|
|||||||
String gbId = gbStream.getGbId();
|
String gbId = gbStream.getGbId();
|
||||||
GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId);
|
GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId);
|
||||||
if (gpsMsgInfo != null) { // 无最新位置不发送
|
if (gpsMsgInfo != null) { // 无最新位置不发送
|
||||||
logger.info("无最新位置不发送");
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("无最新位置不发送");
|
||||||
|
}
|
||||||
// 经纬度都为0不发送
|
// 经纬度都为0不发送
|
||||||
if (gpsMsgInfo.getLng() == 0 && gpsMsgInfo.getLat() == 0) {
|
if (gpsMsgInfo.getLng() == 0 && gpsMsgInfo.getLat() == 0) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -16,6 +16,8 @@ import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
|||||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||||
|
import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
|
||||||
|
import com.genersoft.iot.vmp.service.impl.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 com.genersoft.iot.vmp.utils.SerializeUtils;
|
import com.genersoft.iot.vmp.utils.SerializeUtils;
|
||||||
@ -43,7 +45,7 @@ import java.util.*;
|
|||||||
public class AckRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
|
public class AckRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class);
|
private Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class);
|
||||||
private String method = "ACK";
|
private final String method = "ACK";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SIPProcessorObserver sipProcessorObserver;
|
private SIPProcessorObserver sipProcessorObserver;
|
||||||
@ -78,6 +80,9 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ISIPCommanderForPlatform commanderForPlatform;
|
private ISIPCommanderForPlatform commanderForPlatform;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisGbPlayMsgListener redisGbPlayMsgListener;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理 ACK请求
|
* 处理 ACK请求
|
||||||
@ -114,7 +119,24 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
param.put("pt", sendRtpItem.getPt());
|
param.put("pt", sendRtpItem.getPt());
|
||||||
param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
|
param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
|
||||||
param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
|
param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
|
||||||
|
if (mediaInfo == null) {
|
||||||
|
RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
|
||||||
|
sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(),
|
||||||
|
sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),
|
||||||
|
sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());
|
||||||
|
redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, jsonObject->{
|
||||||
|
startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, jsonObject, param, callIdHeader);
|
||||||
|
});
|
||||||
|
}else {
|
||||||
JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
|
JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
|
||||||
|
startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, jsonObject, param, callIdHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void startSendRtpStreamHand(RequestEvent evt, SendRtpItem sendRtpItem, ParentPlatform parentPlatform,
|
||||||
|
JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader) {
|
||||||
if (jsonObject == null) {
|
if (jsonObject == null) {
|
||||||
logger.error("RTP推流失败: 请检查ZLM服务");
|
logger.error("RTP推流失败: 请检查ZLM服务");
|
||||||
} else if (jsonObject.getInteger("code") == 0) {
|
} else if (jsonObject.getInteger("code") == 0) {
|
||||||
@ -133,59 +155,5 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId());
|
commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if (streamInfo == null) { // 流还没上来,对方就回复ack
|
|
||||||
// logger.info("监听流以等待流上线1 rtp/{}", sendRtpItem.getStreamId());
|
|
||||||
// // 监听流上线
|
|
||||||
// // 添加订阅
|
|
||||||
// JSONObject subscribeKey = new JSONObject();
|
|
||||||
// subscribeKey.put("app", "rtp");
|
|
||||||
// subscribeKey.put("stream", sendRtpItem.getStreamId());
|
|
||||||
// subscribeKey.put("regist", true);
|
|
||||||
// subscribeKey.put("schema", "rtmp");
|
|
||||||
// subscribeKey.put("mediaServerId", sendRtpItem.getMediaServerId());
|
|
||||||
// subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
|
||||||
// (MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
|
||||||
// Map<String, Object> param = new HashMap<>();
|
|
||||||
// param.put("vhost","__defaultVhost__");
|
|
||||||
// param.put("app",json.getString("app"));
|
|
||||||
// param.put("stream",json.getString("stream"));
|
|
||||||
// param.put("ssrc", sendRtpItem.getSsrc());
|
|
||||||
// param.put("dst_url",sendRtpItem.getIp());
|
|
||||||
// param.put("dst_port", sendRtpItem.getPort());
|
|
||||||
// param.put("is_udp", is_Udp);
|
|
||||||
// param.put("src_port", sendRtpItem.getLocalPort());
|
|
||||||
// zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
|
|
||||||
// });
|
|
||||||
// }else {
|
|
||||||
// Map<String, Object> param = new HashMap<>();
|
|
||||||
// param.put("vhost","__defaultVhost__");
|
|
||||||
// param.put("app",streamInfo.getApp());
|
|
||||||
// param.put("stream",streamInfo.getStream());
|
|
||||||
// param.put("ssrc", sendRtpItem.getSsrc());
|
|
||||||
// param.put("dst_url",sendRtpItem.getIp());
|
|
||||||
// param.put("dst_port", sendRtpItem.getPort());
|
|
||||||
// param.put("is_udp", is_Udp);
|
|
||||||
// param.put("src_port", sendRtpItem.getLocalPort());
|
|
||||||
//
|
|
||||||
// JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
|
|
||||||
// if (jsonObject.getInteger("code") != 0) {
|
|
||||||
// logger.info("监听流以等待流上线2 {}/{}", streamInfo.getApp(), streamInfo.getStream());
|
|
||||||
// // 监听流上线
|
|
||||||
// // 添加订阅
|
|
||||||
// JSONObject subscribeKey = new JSONObject();
|
|
||||||
// subscribeKey.put("app", "rtp");
|
|
||||||
// subscribeKey.put("stream", streamInfo.getStream());
|
|
||||||
// subscribeKey.put("regist", true);
|
|
||||||
// subscribeKey.put("schema", "rtmp");
|
|
||||||
// subscribeKey.put("mediaServerId", sendRtpItem.getMediaServerId());
|
|
||||||
// subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
|
||||||
// (MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
|
||||||
// zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,13 +107,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId, null);
|
cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId, null);
|
||||||
}
|
}
|
||||||
if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) {
|
if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) {
|
||||||
MessageForPushChannel messageForPushChannel = new MessageForPushChannel();
|
MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
|
||||||
messageForPushChannel.setType(0);
|
sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(),
|
||||||
messageForPushChannel.setGbId(sendRtpItem.getChannelId());
|
sendRtpItem.getPlatformId(), null, null, sendRtpItem.getMediaServerId());
|
||||||
messageForPushChannel.setApp(sendRtpItem.getApp());
|
|
||||||
messageForPushChannel.setStream(sendRtpItem.getStreamId());
|
|
||||||
messageForPushChannel.setMediaServerId(sendRtpItem.getMediaServerId());
|
|
||||||
messageForPushChannel.setPlatFormId(sendRtpItem.getPlatformId());
|
|
||||||
redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);
|
redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import javax.sip.RequestEvent;
|
|||||||
@Component
|
@Component
|
||||||
public class CancelRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
|
public class CancelRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
|
||||||
|
|
||||||
private String method = "CANCEL";
|
private final String method = "CANCEL";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SIPProcessorObserver sipProcessorObserver;
|
private SIPProcessorObserver sipProcessorObserver;
|
||||||
|
@ -17,10 +17,13 @@ import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
|||||||
import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
|
import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||||
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.IMediaServerService;
|
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||||
import com.genersoft.iot.vmp.service.IPlayService;
|
import com.genersoft.iot.vmp.service.IPlayService;
|
||||||
|
import com.genersoft.iot.vmp.service.IStreamPushService;
|
||||||
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
|
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
|
||||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||||
|
import com.genersoft.iot.vmp.service.impl.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 com.genersoft.iot.vmp.utils.DateUtil;
|
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||||
@ -52,7 +55,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(InviteRequestProcessor.class);
|
private final static Logger logger = LoggerFactory.getLogger(InviteRequestProcessor.class);
|
||||||
|
|
||||||
private String method = "INVITE";
|
private final String method = "INVITE";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SIPCommanderFroPlatform cmderFroPlatform;
|
private SIPCommanderFroPlatform cmderFroPlatform;
|
||||||
@ -60,6 +63,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IVideoManagerStorage storager;
|
private IVideoManagerStorage storager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IStreamPushService streamPushService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IRedisCatchStorage redisCatchStorage;
|
private IRedisCatchStorage redisCatchStorage;
|
||||||
|
|
||||||
@ -94,6 +100,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
private ZLMMediaListManager mediaListManager;
|
private ZLMMediaListManager mediaListManager;
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisGbPlayMsgListener redisGbPlayMsgListener;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
// 添加消息处理的订阅
|
// 添加消息处理的订阅
|
||||||
@ -103,23 +113,23 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
/**
|
/**
|
||||||
* 处理invite请求
|
* 处理invite请求
|
||||||
*
|
*
|
||||||
* @param evt
|
* @param evt 请求消息
|
||||||
* 请求消息
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void process(RequestEvent evt) {
|
public void process(RequestEvent evt) {
|
||||||
// Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令
|
// Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令
|
||||||
try {
|
try {
|
||||||
Request request = evt.getRequest();
|
Request request = evt.getRequest();
|
||||||
SipURI sipURI = (SipURI) request.getRequestURI();
|
SipURI sipUri = (SipURI) request.getRequestURI();
|
||||||
//从subject读取channelId,不再从request-line读取。 有些平台request-line是平台国标编码,不是设备国标编码。
|
//从subject读取channelId,不再从request-line读取。 有些平台request-line是平台国标编码,不是设备国标编码。
|
||||||
//String channelId = sipURI.getUser();
|
//String channelId = sipURI.getUser();
|
||||||
String channelId = SipUtils.getChannelIdFromHeader(request);
|
String channelId = SipUtils.getChannelIdFromHeader(request);
|
||||||
String requesterId = SipUtils.getUserIdFromFromHeader(request);
|
String requesterId = SipUtils.getUserIdFromFromHeader(request);
|
||||||
CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
|
CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
|
||||||
if (requesterId == null || channelId == null) {
|
if (requesterId == null || channelId == null) {
|
||||||
logger.info("无法从FromHeader的Address中获取到平台id,返回400");
|
logger.info("无法从FromHeader的Address中获取到平台id,返回400");
|
||||||
responseAck(evt, Response.BAD_REQUEST); // 参数不全, 发400,请求错误
|
// 参数不全, 发400,请求错误
|
||||||
|
responseAck(evt, Response.BAD_REQUEST);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,30 +137,51 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
|
ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
|
||||||
if (platform == null) {
|
if (platform == null) {
|
||||||
inviteFromDeviceHandle(evt, requesterId);
|
inviteFromDeviceHandle(evt, requesterId);
|
||||||
}else {
|
} else {
|
||||||
// 查询平台下是否有该通道
|
// 查询平台下是否有该通道
|
||||||
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
|
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
|
||||||
GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
|
GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
|
||||||
PlatformCatalog catalog = storager.getCatalog(channelId);
|
PlatformCatalog catalog = storager.getCatalog(channelId);
|
||||||
|
|
||||||
MediaServerItem mediaServerItem = null;
|
MediaServerItem mediaServerItem = null;
|
||||||
|
StreamPushItem streamPushItem = null;
|
||||||
// 不是通道可能是直播流
|
// 不是通道可能是直播流
|
||||||
if (channel != null && gbStream == null ) {
|
if (channel != null && gbStream == null) {
|
||||||
if (channel.getStatus() == 0) {
|
if (channel.getStatus() == 0) {
|
||||||
logger.info("通道离线,返回400");
|
logger.info("通道离线,返回400");
|
||||||
responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline");
|
responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
|
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
|
||||||
}else if(channel == null && gbStream != null){
|
} else if (channel == null && gbStream != null) {
|
||||||
|
|
||||||
String mediaServerId = gbStream.getMediaServerId();
|
String mediaServerId = gbStream.getMediaServerId();
|
||||||
mediaServerItem = mediaServerService.getOne(mediaServerId);
|
mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||||
if (mediaServerItem == null) {
|
if (mediaServerItem == null) {
|
||||||
logger.info("[ app={}, stream={} ]找不到zlm {},返回410",gbStream.getApp(), gbStream.getStream(), mediaServerId);
|
if ("proxy".equals(gbStream.getStreamType())) {
|
||||||
|
logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId);
|
||||||
|
responseAck(evt, Response.GONE);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
streamPushItem = streamPushService.getPush(gbStream.getApp(), gbStream.getStream());
|
||||||
|
if (streamPushItem == null || streamPushItem.getServerId().equals(userSetting.getServerId())) {
|
||||||
|
logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId);
|
||||||
responseAck(evt, Response.GONE);
|
responseAck(evt, Response.GONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ("push".equals(gbStream.getStreamType())) {
|
||||||
|
streamPushItem = streamPushService.getPush(gbStream.getApp(), gbStream.getStream());
|
||||||
|
if (streamPushItem == null) {
|
||||||
|
logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId);
|
||||||
|
responseAck(evt, Response.GONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
|
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
|
||||||
}else if (catalog != null) {
|
} else if (catalog != null) {
|
||||||
responseAck(evt, Response.BAD_REQUEST, "catalog channel can not play"); // 目录不支持点播
|
responseAck(evt, Response.BAD_REQUEST, "catalog channel can not play"); // 目录不支持点播
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -172,7 +203,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
|
ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
|
||||||
String substring = contentString.substring(0, contentString.indexOf("y="));
|
String substring = contentString.substring(0, contentString.indexOf("y="));
|
||||||
sdp = SdpFactory.getInstance().createSessionDescription(substring);
|
sdp = SdpFactory.getInstance().createSessionDescription(substring);
|
||||||
}else {
|
} else {
|
||||||
ssrc = ssrcDefault;
|
ssrc = ssrcDefault;
|
||||||
sdp = SdpFactory.getInstance().createSessionDescription(contentString);
|
sdp = SdpFactory.getInstance().createSessionDescription(contentString);
|
||||||
}
|
}
|
||||||
@ -183,8 +214,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
Instant start = null;
|
Instant start = null;
|
||||||
Instant end = null;
|
Instant end = null;
|
||||||
if (sdp.getTimeDescriptions(false) != null && sdp.getTimeDescriptions(false).size() > 0) {
|
if (sdp.getTimeDescriptions(false) != null && sdp.getTimeDescriptions(false).size() > 0) {
|
||||||
TimeDescriptionImpl timeDescription = (TimeDescriptionImpl)(sdp.getTimeDescriptions(false).get(0));
|
TimeDescriptionImpl timeDescription = (TimeDescriptionImpl) (sdp.getTimeDescriptions(false).get(0));
|
||||||
TimeField startTimeFiled = (TimeField)timeDescription.getTime();
|
TimeField startTimeFiled = (TimeField) timeDescription.getTime();
|
||||||
startTime = startTimeFiled.getStartTime();
|
startTime = startTimeFiled.getStartTime();
|
||||||
stopTime = startTimeFiled.getStopTime();
|
stopTime = startTimeFiled.getStopTime();
|
||||||
|
|
||||||
@ -263,11 +294,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendRtpItem.setCallId(callIdHeader.getCallId());
|
sendRtpItem.setCallId(callIdHeader.getCallId());
|
||||||
sendRtpItem.setPlayType("Play".equals(sessionName)?InviteStreamType.PLAY:InviteStreamType.PLAYBACK);
|
sendRtpItem.setPlayType("Play".equals(sessionName) ? InviteStreamType.PLAY : InviteStreamType.PLAYBACK);
|
||||||
|
|
||||||
Long finalStartTime = startTime;
|
Long finalStartTime = startTime;
|
||||||
Long finalStopTime = stopTime;
|
Long finalStopTime = stopTime;
|
||||||
ZLMHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON)->{
|
ZLMHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON) -> {
|
||||||
String app = responseJSON.getString("app");
|
String app = responseJSON.getString("app");
|
||||||
String stream = responseJSON.getString("stream");
|
String stream = responseJSON.getString("stream");
|
||||||
logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", app, stream);
|
logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", app, stream);
|
||||||
@ -279,28 +310,28 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
|
|
||||||
StringBuffer content = new StringBuffer(200);
|
StringBuffer content = new StringBuffer(200);
|
||||||
content.append("v=0\r\n");
|
content.append("v=0\r\n");
|
||||||
content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
|
content.append("o=" + channelId + " 0 0 IN IP4 " + mediaServerItemInUSe.getSdpIp() + "\r\n");
|
||||||
content.append("s=" + sessionName+"\r\n");
|
content.append("s=" + sessionName + "\r\n");
|
||||||
content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
|
content.append("c=IN IP4 " + mediaServerItemInUSe.getSdpIp() + "\r\n");
|
||||||
if ("Playback".equals(sessionName)) {
|
if ("Playback".equals(sessionName)) {
|
||||||
content.append("t=" + finalStartTime + " " + finalStopTime + "\r\n");
|
content.append("t=" + finalStartTime + " " + finalStopTime + "\r\n");
|
||||||
}else {
|
} else {
|
||||||
content.append("t=0 0\r\n");
|
content.append("t=0 0\r\n");
|
||||||
}
|
}
|
||||||
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
|
content.append("m=video " + sendRtpItem.getLocalPort() + " RTP/AVP 96\r\n");
|
||||||
content.append("a=sendonly\r\n");
|
content.append("a=sendonly\r\n");
|
||||||
content.append("a=rtpmap:96 PS/90000\r\n");
|
content.append("a=rtpmap:96 PS/90000\r\n");
|
||||||
content.append("y="+ ssrc + "\r\n");
|
content.append("y=" + ssrc + "\r\n");
|
||||||
content.append("f=\r\n");
|
content.append("f=\r\n");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 超时未收到Ack应该回复bye,当前等待时间为10秒
|
// 超时未收到Ack应该回复bye,当前等待时间为10秒
|
||||||
dynamicTask.startDelay(callIdHeader.getCallId(), ()->{
|
dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
|
||||||
logger.info("Ack 等待超时");
|
logger.info("Ack 等待超时");
|
||||||
mediaServerService.releaseSsrc(mediaServerItemInUSe.getId(), ssrc);
|
mediaServerService.releaseSsrc(mediaServerItemInUSe.getId(), ssrc);
|
||||||
// 回复bye
|
// 回复bye
|
||||||
cmderFroPlatform.streamByeCmd(platform, callIdHeader.getCallId());
|
cmderFroPlatform.streamByeCmd(platform, callIdHeader.getCallId());
|
||||||
}, 60*1000);
|
}, 60 * 1000);
|
||||||
responseSdpAck(evt, content.toString(), platform);
|
responseSdpAck(evt, content.toString(), platform);
|
||||||
|
|
||||||
} catch (SipException e) {
|
} catch (SipException e) {
|
||||||
@ -334,7 +365,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
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),
|
||||||
DateUtil.formatter.format(end), null, result -> {
|
DateUtil.formatter.format(end), null, result -> {
|
||||||
if (result.getCode() != 0){
|
if (result.getCode() != 0) {
|
||||||
logger.warn("录像回放失败");
|
logger.warn("录像回放失败");
|
||||||
if (result.getEvent() != null) {
|
if (result.getEvent() != null) {
|
||||||
errorEvent.response(result.getEvent());
|
errorEvent.response(result.getEvent());
|
||||||
@ -349,13 +380,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
if (result.getMediaServerItem() != null) {
|
if (result.getMediaServerItem() != null) {
|
||||||
hookEvent.response(result.getMediaServerItem(), result.getResponse());
|
hookEvent.response(result.getMediaServerItem(), result.getResponse());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}else {
|
} else {
|
||||||
sendRtpItem.setPlayType(InviteStreamType.PLAY);
|
sendRtpItem.setPlayType(InviteStreamType.PLAY);
|
||||||
SsrcTransaction playTransaction = sessionManager.getSsrcTransaction(device.getDeviceId(), channelId, "play", null);
|
SsrcTransaction playTransaction = sessionManager.getSsrcTransaction(device.getDeviceId(), channelId, "play", null);
|
||||||
if (playTransaction != null) {
|
if (playTransaction != null) {
|
||||||
@ -373,11 +404,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
sendRtpItem.setStreamId(ssrcInfo.getStream());
|
sendRtpItem.setStreamId(ssrcInfo.getStream());
|
||||||
// 写入redis, 超时时回复
|
// 写入redis, 超时时回复
|
||||||
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||||
playService.play(mediaServerItem, ssrcInfo, device, channelId, hookEvent, errorEvent, (code, msg)->{
|
playService.play(mediaServerItem, ssrcInfo, device, channelId, hookEvent, errorEvent, (code, msg) -> {
|
||||||
logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId);
|
logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId);
|
||||||
redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
|
redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
|
||||||
}, null);
|
}, null);
|
||||||
}else {
|
} else {
|
||||||
sendRtpItem.setStreamId(playTransaction.getStream());
|
sendRtpItem.setStreamId(playTransaction.getStream());
|
||||||
// 写入redis, 超时时回复
|
// 写入redis, 超时时回复
|
||||||
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||||
@ -387,33 +418,106 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
hookEvent.response(mediaServerItem, jsonObject);
|
hookEvent.response(mediaServerItem, jsonObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if (gbStream != null) {
|
} else if (gbStream != null) {
|
||||||
|
if (streamPushItem.isStatus()) {
|
||||||
|
// 在线状态
|
||||||
|
pushStream(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
|
||||||
|
mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
|
||||||
|
} else {
|
||||||
|
// 不在线 拉起
|
||||||
|
notifyStreamOnline(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
|
||||||
|
mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
logger.warn("sdp解析错误");
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (SdpParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (SdpException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安排推流
|
||||||
|
*/
|
||||||
|
|
||||||
|
private void pushStream(RequestEvent evt, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
|
||||||
|
CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
|
||||||
|
int port, Boolean tcpActive, boolean mediaTransmissionTCP,
|
||||||
|
String channelId, String addressStr, String ssrc, String requesterId) throws InvalidArgumentException, ParseException, SipException {
|
||||||
|
// 推流
|
||||||
|
if (streamPushItem.getServerId().equals(userSetting.getServerId())) {
|
||||||
Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
|
Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
|
||||||
if (!streamReady ) {
|
if (streamReady) {
|
||||||
|
// 自平台内容
|
||||||
|
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
|
||||||
|
gbStream.getApp(), gbStream.getStream(), channelId,
|
||||||
|
mediaTransmissionTCP);
|
||||||
|
|
||||||
|
if (sendRtpItem == null) {
|
||||||
|
logger.warn("服务器端口资源不足");
|
||||||
|
responseAck(evt, Response.BUSY_HERE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (tcpActive != null) {
|
||||||
|
sendRtpItem.setTcpActive(tcpActive);
|
||||||
|
}
|
||||||
|
sendRtpItem.setPlayType(InviteStreamType.PUSH);
|
||||||
|
// 写入redis, 超时时回复
|
||||||
|
sendRtpItem.setStatus(1);
|
||||||
|
sendRtpItem.setCallId(callIdHeader.getCallId());
|
||||||
|
byte[] dialogByteArray = SerializeUtils.serialize(evt.getDialog());
|
||||||
|
sendRtpItem.setDialog(dialogByteArray);
|
||||||
|
byte[] transactionByteArray = SerializeUtils.serialize(evt.getServerTransaction());
|
||||||
|
sendRtpItem.setTransaction(transactionByteArray);
|
||||||
|
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||||
|
sendStreamAck(mediaServerItem, sendRtpItem, platform, evt);
|
||||||
|
} else {
|
||||||
|
// 不在线 拉起
|
||||||
|
notifyStreamOnline(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
|
||||||
|
mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 其他平台内容
|
||||||
|
otherWvpPushStream(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
|
||||||
|
mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知流上线
|
||||||
|
*/
|
||||||
|
private void notifyStreamOnline(RequestEvent evt, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
|
||||||
|
CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
|
||||||
|
int port, Boolean tcpActive, boolean mediaTransmissionTCP,
|
||||||
|
String channelId, String addressStr, String ssrc, String requesterId) throws InvalidArgumentException, ParseException, SipException {
|
||||||
if ("proxy".equals(gbStream.getStreamType())) {
|
if ("proxy".equals(gbStream.getStreamType())) {
|
||||||
// TODO 控制启用以使设备上线
|
// TODO 控制启用以使设备上线
|
||||||
logger.info("[ app={}, stream={} ]通道离线,启用流后开始推流",gbStream.getApp(), gbStream.getStream());
|
logger.info("[ app={}, stream={} ]通道离线,启用流后开始推流", gbStream.getApp(), gbStream.getStream());
|
||||||
responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
|
responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
|
||||||
}else if ("push".equals(gbStream.getStreamType())) {
|
} else if ("push".equals(gbStream.getStreamType())) {
|
||||||
if (!platform.isStartOfflinePush()) {
|
if (!platform.isStartOfflinePush()) {
|
||||||
responseAck(evt, Response.TEMPORARILY_UNAVAILABLE, "channel unavailable");
|
responseAck(evt, Response.TEMPORARILY_UNAVAILABLE, "channel unavailable");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 发送redis消息以使设备上线
|
// 发送redis消息以使设备上线
|
||||||
logger.info("[ app={}, stream={} ]通道离线,发送redis信息控制设备开始推流",gbStream.getApp(), gbStream.getStream());
|
logger.info("[ app={}, stream={} ]通道离线,发送redis信息控制设备开始推流", gbStream.getApp(), gbStream.getStream());
|
||||||
MessageForPushChannel messageForPushChannel = new MessageForPushChannel();
|
|
||||||
messageForPushChannel.setType(1);
|
MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(1,
|
||||||
messageForPushChannel.setGbId(gbStream.getGbId());
|
gbStream.getApp(), gbStream.getStream(), gbStream.getGbId(), gbStream.getPlatformId(),
|
||||||
messageForPushChannel.setApp(gbStream.getApp());
|
platform.getName(), null, gbStream.getMediaServerId());
|
||||||
messageForPushChannel.setStream(gbStream.getStream());
|
|
||||||
// TODO 获取低负载的节点
|
|
||||||
messageForPushChannel.setMediaServerId(gbStream.getMediaServerId());
|
|
||||||
messageForPushChannel.setPlatFormId(platform.getServerGBId());
|
|
||||||
messageForPushChannel.setPlatFormName(platform.getName());
|
|
||||||
redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);
|
redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);
|
||||||
// 设置超时
|
// 设置超时
|
||||||
dynamicTask.startDelay(callIdHeader.getCallId(), ()->{
|
dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
|
||||||
logger.info("[ app={}, stream={} ] 等待设备开始推流超时", gbStream.getApp(), gbStream.getStream());
|
logger.info("[ app={}, stream={} ] 等待设备开始推流超时", gbStream.getApp(), gbStream.getStream());
|
||||||
try {
|
try {
|
||||||
mediaListManager.removedChannelOnlineEventLister(gbStream.getGbId());
|
mediaListManager.removedChannelOnlineEventLister(gbStream.getGbId());
|
||||||
@ -427,13 +531,15 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
}
|
}
|
||||||
}, userSetting.getPlatformPlayTimeout());
|
}, userSetting.getPlatformPlayTimeout());
|
||||||
// 添加监听
|
// 添加监听
|
||||||
MediaServerItem finalMediaServerItem = mediaServerItem;
|
|
||||||
int finalPort = port;
|
int finalPort = port;
|
||||||
boolean finalMediaTransmissionTCP = mediaTransmissionTCP;
|
|
||||||
Boolean finalTcpActive = tcpActive;
|
Boolean finalTcpActive = tcpActive;
|
||||||
mediaListManager.addChannelOnlineEventLister(gbStream.getGbId(), (app, stream)->{
|
|
||||||
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(finalMediaServerItem, addressStr, finalPort, ssrc, requesterId,
|
// 添加在本机上线的通知
|
||||||
app, stream, channelId, finalMediaTransmissionTCP);
|
mediaListManager.addChannelOnlineEventLister(gbStream.getGbId(), (app, stream, serverId) -> {
|
||||||
|
dynamicTask.stop(callIdHeader.getCallId());
|
||||||
|
if (serverId.equals(userSetting.getServerId())) {
|
||||||
|
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, finalPort, ssrc, requesterId,
|
||||||
|
app, stream, channelId, mediaTransmissionTCP);
|
||||||
|
|
||||||
if (sendRtpItem == null) {
|
if (sendRtpItem == null) {
|
||||||
logger.warn("服务器端口资源不足");
|
logger.warn("服务器端口资源不足");
|
||||||
@ -460,21 +566,43 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
byte[] transactionByteArray = SerializeUtils.serialize(evt.getServerTransaction());
|
byte[] transactionByteArray = SerializeUtils.serialize(evt.getServerTransaction());
|
||||||
sendRtpItem.setTransaction(transactionByteArray);
|
sendRtpItem.setTransaction(transactionByteArray);
|
||||||
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||||
sendStreamAck(finalMediaServerItem, sendRtpItem, platform, evt);
|
sendStreamAck(mediaServerItem, sendRtpItem, platform, evt);
|
||||||
|
} else {
|
||||||
|
// 其他平台内容
|
||||||
|
otherWvpPushStream(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
|
||||||
|
mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}else {
|
}
|
||||||
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
|
|
||||||
gbStream.getApp(), gbStream.getStream(), channelId,
|
|
||||||
mediaTransmissionTCP);
|
|
||||||
|
|
||||||
|
/**
|
||||||
if (sendRtpItem == null) {
|
* 来自其他wvp的推流
|
||||||
|
*/
|
||||||
|
private void otherWvpPushStream(RequestEvent evt, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
|
||||||
|
CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
|
||||||
|
int port, Boolean tcpActive, boolean mediaTransmissionTCP,
|
||||||
|
String channelId, String addressStr, String ssrc, String requesterId) {
|
||||||
|
logger.info("[级联点播]直播流来自其他平台,发送redis消息");
|
||||||
|
// 发送redis消息
|
||||||
|
redisGbPlayMsgListener.sendMsg(streamPushItem.getServerId(), streamPushItem.getMediaServerId(),
|
||||||
|
streamPushItem.getApp(), streamPushItem.getStream(), addressStr, port, ssrc, requesterId,
|
||||||
|
channelId, mediaTransmissionTCP, null, responseSendItemMsg -> {
|
||||||
|
SendRtpItem sendRtpItem = responseSendItemMsg.getSendRtpItem();
|
||||||
|
if (sendRtpItem == null || responseSendItemMsg.getMediaServerItem() == null) {
|
||||||
logger.warn("服务器端口资源不足");
|
logger.warn("服务器端口资源不足");
|
||||||
|
try {
|
||||||
responseAck(evt, Response.BUSY_HERE);
|
responseAck(evt, Response.BUSY_HERE);
|
||||||
|
} catch (SipException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvalidArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (ParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 收到sendItem
|
||||||
if (tcpActive != null) {
|
if (tcpActive != null) {
|
||||||
sendRtpItem.setTcpActive(tcpActive);
|
sendRtpItem.setTcpActive(tcpActive);
|
||||||
}
|
}
|
||||||
@ -487,45 +615,67 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
byte[] transactionByteArray = SerializeUtils.serialize(evt.getServerTransaction());
|
byte[] transactionByteArray = SerializeUtils.serialize(evt.getServerTransaction());
|
||||||
sendRtpItem.setTransaction(transactionByteArray);
|
sendRtpItem.setTransaction(transactionByteArray);
|
||||||
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||||
sendStreamAck(mediaServerItem, sendRtpItem, platform, evt);
|
sendStreamAck(responseSendItemMsg.getMediaServerItem(), sendRtpItem, platform, evt);
|
||||||
|
}, (wvpResult) -> {
|
||||||
|
try {
|
||||||
|
// 错误
|
||||||
|
if (wvpResult.getCode() == RedisGbPlayMsgListener.ERROR_CODE_OFFLINE) {
|
||||||
|
// 离线
|
||||||
|
// 查询是否在本机上线了
|
||||||
|
StreamPushItem currentStreamPushItem = streamPushService.getPush(streamPushItem.getApp(), streamPushItem.getStream());
|
||||||
|
if (currentStreamPushItem.isStatus()) {
|
||||||
|
// 在线状态
|
||||||
|
pushStream(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
|
||||||
|
mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 不在线 拉起
|
||||||
|
notifyStreamOnline(evt, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
|
||||||
|
mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InvalidArgumentException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (SipException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
try {
|
||||||
|
responseAck(evt, Response.BUSY_HERE);
|
||||||
}
|
} catch (SipException e) {
|
||||||
|
|
||||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
logger.warn("sdp解析错误");
|
} catch (InvalidArgumentException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (SdpParseException e) {
|
} catch (ParseException e) {
|
||||||
e.printStackTrace();
|
|
||||||
} catch (SdpException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendStreamAck(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, ParentPlatform platform, RequestEvent evt){
|
public void sendStreamAck(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, ParentPlatform platform, RequestEvent evt) {
|
||||||
|
|
||||||
StringBuffer content = new StringBuffer(200);
|
StringBuffer content = new StringBuffer(200);
|
||||||
content.append("v=0\r\n");
|
content.append("v=0\r\n");
|
||||||
content.append("o="+ sendRtpItem.getChannelId() +" 0 0 IN IP4 "+ mediaServerItem.getSdpIp()+"\r\n");
|
content.append("o=" + sendRtpItem.getChannelId() + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
|
||||||
content.append("s=Play\r\n");
|
content.append("s=Play\r\n");
|
||||||
content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
|
content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
|
||||||
content.append("t=0 0\r\n");
|
content.append("t=0 0\r\n");
|
||||||
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
|
content.append("m=video " + sendRtpItem.getLocalPort() + " RTP/AVP 96\r\n");
|
||||||
content.append("a=sendonly\r\n");
|
content.append("a=sendonly\r\n");
|
||||||
content.append("a=rtpmap:96 PS/90000\r\n");
|
content.append("a=rtpmap:96 PS/90000\r\n");
|
||||||
if (sendRtpItem.isTcp()) {
|
if (sendRtpItem.isTcp()) {
|
||||||
content.append("a=connection:new\r\n");
|
content.append("a=connection:new\r\n");
|
||||||
if (!sendRtpItem.isTcpActive()) {
|
if (!sendRtpItem.isTcpActive()) {
|
||||||
content.append("a=setup:active\r\n");
|
content.append("a=setup:active\r\n");
|
||||||
}else {
|
} else {
|
||||||
content.append("a=setup:passive\r\n");
|
content.append("a=setup:passive\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
content.append("y="+ sendRtpItem.getSsrc() + "\r\n");
|
content.append("y=" + sendRtpItem.getSsrc() + "\r\n");
|
||||||
content.append("f=\r\n");
|
content.append("f=\r\n");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -571,7 +721,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
|||||||
boolean mediaTransmissionTCP = false;
|
boolean mediaTransmissionTCP = false;
|
||||||
Boolean tcpActive = null;
|
Boolean tcpActive = null;
|
||||||
for (int i = 0; i < mediaDescriptions.size(); i++) {
|
for (int i = 0; i < mediaDescriptions.size(); i++) {
|
||||||
MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
|
MediaDescription mediaDescription = (MediaDescription) mediaDescriptions.get(i);
|
||||||
Media media = mediaDescription.getMedia();
|
Media media = mediaDescription.getMedia();
|
||||||
|
|
||||||
Vector mediaFormats = media.getMediaFormats(false);
|
Vector mediaFormats = media.getMediaFormats(false);
|
||||||
|
@ -41,7 +41,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
|
|||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(RegisterRequestProcessor.class);
|
private final Logger logger = LoggerFactory.getLogger(RegisterRequestProcessor.class);
|
||||||
|
|
||||||
public String method = "REGISTER";
|
public final String method = "REGISTER";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SipConfig sipConfig;
|
private SipConfig sipConfig;
|
||||||
|
@ -40,9 +40,7 @@ import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
|
|||||||
public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
|
public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(RecordInfoResponseMessageHandler.class);
|
private Logger logger = LoggerFactory.getLogger(RecordInfoResponseMessageHandler.class);
|
||||||
public static volatile List<String> threadNameList = new ArrayList();
|
|
||||||
private final String cmdType = "RecordInfo";
|
private final String cmdType = "RecordInfo";
|
||||||
private final static String CACHE_RECORDINFO_KEY = "CACHE_RECORDINFO_";
|
|
||||||
|
|
||||||
private ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>();
|
private ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ import javax.sip.ResponseEvent;
|
|||||||
@Component
|
@Component
|
||||||
public class ByeResponseProcessor extends SIPResponseProcessorAbstract {
|
public class ByeResponseProcessor extends SIPResponseProcessorAbstract {
|
||||||
|
|
||||||
private String method = "BYE";
|
private final String method = "BYE";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SipLayer sipLayer;
|
private SipLayer sipLayer;
|
||||||
|
@ -17,7 +17,7 @@ import javax.sip.ResponseEvent;
|
|||||||
@Component
|
@Component
|
||||||
public class CancelResponseProcessor extends SIPResponseProcessorAbstract {
|
public class CancelResponseProcessor extends SIPResponseProcessorAbstract {
|
||||||
|
|
||||||
private String method = "CANCEL";
|
private final String method = "CANCEL";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SipLayer sipLayer;
|
private SipLayer sipLayer;
|
||||||
|
@ -31,7 +31,7 @@ import java.text.ParseException;
|
|||||||
public class InviteResponseProcessor extends SIPResponseProcessorAbstract {
|
public class InviteResponseProcessor extends SIPResponseProcessorAbstract {
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class);
|
private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class);
|
||||||
private String method = "INVITE";
|
private final String method = "INVITE";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SipLayer sipLayer;
|
private SipLayer sipLayer;
|
||||||
|
@ -27,7 +27,7 @@ import javax.sip.message.Response;
|
|||||||
public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
|
public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(RegisterResponseProcessor.class);
|
private Logger logger = LoggerFactory.getLogger(RegisterResponseProcessor.class);
|
||||||
private String method = "REGISTER";
|
private final String method = "REGISTER";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISIPCommanderForPlatform sipCommanderForPlatform;
|
private ISIPCommanderForPlatform sipCommanderForPlatform;
|
||||||
|
@ -397,21 +397,22 @@ public class ZLMHttpHookListener {
|
|||||||
if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal()
|
if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal()
|
||||||
|| item.getOriginType() == OriginType.RTMP_PUSH.ordinal()
|
|| item.getOriginType() == OriginType.RTMP_PUSH.ordinal()
|
||||||
|| item.getOriginType() == OriginType.RTC_PUSH.ordinal() ) {
|
|| item.getOriginType() == OriginType.RTC_PUSH.ordinal() ) {
|
||||||
streamPushItem = zlmMediaListManager.addPush(item);
|
item.setSeverId(userSetting.getServerId());
|
||||||
|
zlmMediaListManager.addPush(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<GbStream> gbStreams = new ArrayList<>();
|
// List<GbStream> gbStreams = new ArrayList<>();
|
||||||
if (streamPushItem == null || streamPushItem.getGbId() == null) {
|
// if (streamPushItem == null || streamPushItem.getGbId() == null) {
|
||||||
GbStream gbStream = storager.getGbStream(app, streamId);
|
// GbStream gbStream = storager.getGbStream(app, streamId);
|
||||||
gbStreams.add(gbStream);
|
// gbStreams.add(gbStream);
|
||||||
}else {
|
// }else {
|
||||||
if (streamPushItem.getGbId() != null) {
|
// if (streamPushItem.getGbId() != null) {
|
||||||
gbStreams.add(streamPushItem);
|
// gbStreams.add(streamPushItem);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if (gbStreams.size() > 0) {
|
// if (gbStreams.size() > 0) {
|
||||||
// eventPublisher.catalogEventPublishForStream(null, gbStreams, CatalogEvent.ON);
|
// eventPublisher.catalogEventPublishForStream(null, gbStreams, CatalogEvent.ON);
|
||||||
}
|
// }
|
||||||
|
|
||||||
}else {
|
}else {
|
||||||
// 兼容流注销时类型从redis记录获取
|
// 兼容流注销时类型从redis记录获取
|
||||||
|
@ -24,6 +24,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class ZLMMediaListManager {
|
public class ZLMMediaListManager {
|
||||||
|
|
||||||
@ -147,7 +150,6 @@ public class ZLMMediaListManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// StreamProxyItem streamProxyItem = gbStreamMapper.selectOne(transform.getApp(), transform.getStream());
|
|
||||||
List<GbStream> gbStreamList = gbStreamMapper.selectByGBId(transform.getGbId());
|
List<GbStream> gbStreamList = gbStreamMapper.selectByGBId(transform.getGbId());
|
||||||
if (gbStreamList != null && gbStreamList.size() == 1) {
|
if (gbStreamList != null && gbStreamList.size() == 1) {
|
||||||
transform.setGbStreamId(gbStreamList.get(0).getGbStreamId());
|
transform.setGbStreamId(gbStreamList.get(0).getGbStreamId());
|
||||||
@ -162,13 +164,12 @@ public class ZLMMediaListManager {
|
|||||||
}
|
}
|
||||||
if (transform != null) {
|
if (transform != null) {
|
||||||
if (channelOnlineEvents.get(transform.getGbId()) != null) {
|
if (channelOnlineEvents.get(transform.getGbId()) != null) {
|
||||||
channelOnlineEvents.get(transform.getGbId()).run(transform.getApp(), transform.getStream());
|
channelOnlineEvents.get(transform.getGbId()).run(transform.getApp(), transform.getStream(), transform.getServerId());
|
||||||
channelOnlineEvents.remove(transform.getGbId());
|
channelOnlineEvents.remove(transform.getGbId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
storager.updateMedia(transform);
|
storager.updateMedia(transform);
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.media.zlm;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -20,6 +21,9 @@ public class ZLMRTPServerFactory {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserSetting userSetting;
|
||||||
|
|
||||||
private int[] portRangeArray = new int[2];
|
private int[] portRangeArray = new int[2];
|
||||||
|
|
||||||
public int getFreePort(MediaServerItem mediaServerItem, int startPort, int endPort, List<Integer> usedFreelist) {
|
public int getFreePort(MediaServerItem mediaServerItem, int startPort, int endPort, List<Integer> usedFreelist) {
|
||||||
@ -197,6 +201,7 @@ public class ZLMRTPServerFactory {
|
|||||||
sendRtpItem.setTcp(tcp);
|
sendRtpItem.setTcp(tcp);
|
||||||
sendRtpItem.setApp("rtp");
|
sendRtpItem.setApp("rtp");
|
||||||
sendRtpItem.setLocalPort(localPort);
|
sendRtpItem.setLocalPort(localPort);
|
||||||
|
sendRtpItem.setServerId(userSetting.getServerId());
|
||||||
sendRtpItem.setMediaServerId(serverItem.getId());
|
sendRtpItem.setMediaServerId(serverItem.getId());
|
||||||
return sendRtpItem;
|
return sendRtpItem;
|
||||||
}
|
}
|
||||||
@ -238,6 +243,7 @@ public class ZLMRTPServerFactory {
|
|||||||
sendRtpItem.setChannelId(channelId);
|
sendRtpItem.setChannelId(channelId);
|
||||||
sendRtpItem.setTcp(tcp);
|
sendRtpItem.setTcp(tcp);
|
||||||
sendRtpItem.setLocalPort(localPort);
|
sendRtpItem.setLocalPort(localPort);
|
||||||
|
sendRtpItem.setServerId(userSetting.getServerId());
|
||||||
sendRtpItem.setMediaServerId(serverItem.getId());
|
sendRtpItem.setMediaServerId(serverItem.getId());
|
||||||
return sendRtpItem;
|
return sendRtpItem;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
package com.genersoft.iot.vmp.media.zlm.dto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
public interface ChannelOnlineEvent {
|
public interface ChannelOnlineEvent {
|
||||||
|
|
||||||
void run(String app, String stream);
|
void run(String app, String stream, String serverId);
|
||||||
}
|
}
|
||||||
|
@ -61,10 +61,15 @@ public class MediaItem {
|
|||||||
private String originUrl;
|
private String originUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器id
|
* 流媒体服务器id
|
||||||
*/
|
*/
|
||||||
private String mediaServerId;
|
private String mediaServerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器id
|
||||||
|
*/
|
||||||
|
private String severId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GMT unix系统时间戳,单位秒
|
* GMT unix系统时间戳,单位秒
|
||||||
*/
|
*/
|
||||||
@ -414,4 +419,12 @@ public class MediaItem {
|
|||||||
public void setStreamInfo(StreamInfo streamInfo) {
|
public void setStreamInfo(StreamInfo streamInfo) {
|
||||||
this.streamInfo = streamInfo;
|
this.streamInfo = streamInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSeverId() {
|
||||||
|
return severId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeverId(String severId) {
|
||||||
|
this.severId = severId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,11 @@ public class StreamPushItem extends GbStream implements Comparable<StreamPushIte
|
|||||||
*/
|
*/
|
||||||
private String mediaServerId;
|
private String mediaServerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用的服务ID
|
||||||
|
*/
|
||||||
|
private String serverId;
|
||||||
|
|
||||||
public String getVhost() {
|
public String getVhost() {
|
||||||
return vhost;
|
return vhost;
|
||||||
}
|
}
|
||||||
@ -219,5 +224,13 @@ public class StreamPushItem extends GbStream implements Comparable<StreamPushIte
|
|||||||
public void setMediaServerId(String mediaServerId) {
|
public void setMediaServerId(String mediaServerId) {
|
||||||
this.mediaServerId = mediaServerId;
|
this.mediaServerId = mediaServerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getServerId() {
|
||||||
|
return serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerId(String serverId) {
|
||||||
|
this.serverId = serverId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ public class StreamGPSSubscribeTask {
|
|||||||
private IVideoManagerStorage storager;
|
private IVideoManagerStorage storager;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Scheduled(fixedRate = 30 * 1000) //每30秒执行一次
|
@Scheduled(fixedRate = 30 * 1000) //每30秒执行一次
|
||||||
public void execute(){
|
public void execute(){
|
||||||
List<GPSMsgInfo> gpsMsgInfo = redisCatchStorage.getAllGpsMsgInfo();
|
List<GPSMsgInfo> gpsMsgInfo = redisCatchStorage.getAllGpsMsgInfo();
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package com.genersoft.iot.vmp.service.bean;
|
package com.genersoft.iot.vmp.service.bean;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当上级平台
|
* 当上级平台
|
||||||
|
* @author lin
|
||||||
*/
|
*/
|
||||||
public class MessageForPushChannel {
|
public class MessageForPushChannel {
|
||||||
/**
|
/**
|
||||||
@ -45,6 +48,20 @@ public class MessageForPushChannel {
|
|||||||
*/
|
*/
|
||||||
private String mediaServerId;
|
private String mediaServerId;
|
||||||
|
|
||||||
|
public static MessageForPushChannel getInstance(int type, String app, String stream, String gbId,
|
||||||
|
String platFormId, String platFormName, String serverId,
|
||||||
|
String mediaServerId){
|
||||||
|
MessageForPushChannel messageForPushChannel = new MessageForPushChannel();
|
||||||
|
messageForPushChannel.setType(type);
|
||||||
|
messageForPushChannel.setGbId(gbId);
|
||||||
|
messageForPushChannel.setApp(app);
|
||||||
|
messageForPushChannel.setStream(stream);
|
||||||
|
messageForPushChannel.setMediaServerId(mediaServerId);
|
||||||
|
messageForPushChannel.setPlatFormId(platFormId);
|
||||||
|
messageForPushChannel.setPlatFormName(platFormName);
|
||||||
|
return messageForPushChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return type;
|
return type;
|
||||||
|
@ -0,0 +1,170 @@
|
|||||||
|
package com.genersoft.iot.vmp.service.bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis消息:请求下级推送流信息
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
|
public class RequestPushStreamMsg {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下级服务ID
|
||||||
|
*/
|
||||||
|
private String mediaServerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流ID
|
||||||
|
*/
|
||||||
|
private String app;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用名
|
||||||
|
*/
|
||||||
|
private String stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目标IP
|
||||||
|
*/
|
||||||
|
private String ip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目标端口
|
||||||
|
*/
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ssrc
|
||||||
|
*/
|
||||||
|
private String ssrc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否使用TCP方式
|
||||||
|
*/
|
||||||
|
private boolean tcp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地使用的端口
|
||||||
|
*/
|
||||||
|
private int srcPort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送时,rtp的pt(uint8_t),不传时默认为96
|
||||||
|
*/
|
||||||
|
private int pt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送时,rtp的负载类型。为true时,负载为ps;为false时,为es;
|
||||||
|
*/
|
||||||
|
private boolean ps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否只有音频
|
||||||
|
*/
|
||||||
|
private boolean onlyAudio;
|
||||||
|
|
||||||
|
|
||||||
|
public static RequestPushStreamMsg getInstance(String mediaServerId, String app, String stream, String ip, int port, String ssrc,
|
||||||
|
boolean tcp, int srcPort, int pt, boolean ps, boolean onlyAudio) {
|
||||||
|
RequestPushStreamMsg requestPushStreamMsg = new RequestPushStreamMsg();
|
||||||
|
requestPushStreamMsg.setMediaServerId(mediaServerId);
|
||||||
|
requestPushStreamMsg.setApp(app);
|
||||||
|
requestPushStreamMsg.setStream(stream);
|
||||||
|
requestPushStreamMsg.setIp(ip);
|
||||||
|
requestPushStreamMsg.setPort(port);
|
||||||
|
requestPushStreamMsg.setSsrc(ssrc);
|
||||||
|
requestPushStreamMsg.setTcp(tcp);
|
||||||
|
requestPushStreamMsg.setSrcPort(srcPort);
|
||||||
|
requestPushStreamMsg.setPt(pt);
|
||||||
|
requestPushStreamMsg.setPs(ps);
|
||||||
|
requestPushStreamMsg.setOnlyAudio(onlyAudio);
|
||||||
|
return requestPushStreamMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMediaServerId() {
|
||||||
|
return mediaServerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServerId(String mediaServerId) {
|
||||||
|
this.mediaServerId = mediaServerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApp() {
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApp(String app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStream(String stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIp() {
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIp(String ip) {
|
||||||
|
this.ip = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSsrc() {
|
||||||
|
return ssrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSsrc(String ssrc) {
|
||||||
|
this.ssrc = ssrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTcp() {
|
||||||
|
return tcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTcp(boolean tcp) {
|
||||||
|
this.tcp = tcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSrcPort() {
|
||||||
|
return srcPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSrcPort(int srcPort) {
|
||||||
|
this.srcPort = srcPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPt() {
|
||||||
|
return pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPt(int pt) {
|
||||||
|
this.pt = pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPs() {
|
||||||
|
return ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPs(boolean ps) {
|
||||||
|
this.ps = ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOnlyAudio() {
|
||||||
|
return onlyAudio;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnlyAudio(boolean onlyAudio) {
|
||||||
|
this.onlyAudio = onlyAudio;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,173 @@
|
|||||||
|
package com.genersoft.iot.vmp.service.bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis消息:请求下级回复推送信息
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
|
public class RequestSendItemMsg {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下级服务ID
|
||||||
|
*/
|
||||||
|
private String serverId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下级服务ID
|
||||||
|
*/
|
||||||
|
private String mediaServerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流ID
|
||||||
|
*/
|
||||||
|
private String app;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用名
|
||||||
|
*/
|
||||||
|
private String stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目标IP
|
||||||
|
*/
|
||||||
|
private String ip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目标端口
|
||||||
|
*/
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ssrc
|
||||||
|
*/
|
||||||
|
private String ssrc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 平台国标编号
|
||||||
|
*/
|
||||||
|
private String platformId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 平台名称
|
||||||
|
*/
|
||||||
|
private String platformName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通道ID
|
||||||
|
*/
|
||||||
|
private String channelId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否使用TCP
|
||||||
|
*/
|
||||||
|
private Boolean isTcp;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static RequestSendItemMsg getInstance(String serverId, String mediaServerId, String app, String stream, String ip, int port,
|
||||||
|
String ssrc, String platformId, String channelId, Boolean isTcp, String platformName) {
|
||||||
|
RequestSendItemMsg requestSendItemMsg = new RequestSendItemMsg();
|
||||||
|
requestSendItemMsg.setServerId(serverId);
|
||||||
|
requestSendItemMsg.setMediaServerId(mediaServerId);
|
||||||
|
requestSendItemMsg.setApp(app);
|
||||||
|
requestSendItemMsg.setStream(stream);
|
||||||
|
requestSendItemMsg.setIp(ip);
|
||||||
|
requestSendItemMsg.setPort(port);
|
||||||
|
requestSendItemMsg.setSsrc(ssrc);
|
||||||
|
requestSendItemMsg.setPlatformId(platformId);
|
||||||
|
requestSendItemMsg.setPlatformName(platformName);
|
||||||
|
requestSendItemMsg.setChannelId(channelId);
|
||||||
|
requestSendItemMsg.setTcp(isTcp);
|
||||||
|
|
||||||
|
return requestSendItemMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerId() {
|
||||||
|
return serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerId(String serverId) {
|
||||||
|
this.serverId = serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMediaServerId() {
|
||||||
|
return mediaServerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServerId(String mediaServerId) {
|
||||||
|
this.mediaServerId = mediaServerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApp() {
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApp(String app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStream(String stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIp() {
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIp(String ip) {
|
||||||
|
this.ip = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSsrc() {
|
||||||
|
return ssrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSsrc(String ssrc) {
|
||||||
|
this.ssrc = ssrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPlatformId() {
|
||||||
|
return platformId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPlatformId(String platformId) {
|
||||||
|
this.platformId = platformId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPlatformName() {
|
||||||
|
return platformName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPlatformName(String platformName) {
|
||||||
|
this.platformName = platformName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChannelId() {
|
||||||
|
return channelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChannelId(String channelId) {
|
||||||
|
this.channelId = channelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getTcp() {
|
||||||
|
return isTcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTcp(Boolean tcp) {
|
||||||
|
isTcp = tcp;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.genersoft.iot.vmp.service.bean;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis消息:下级回复推送信息
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
|
public class ResponseSendItemMsg {
|
||||||
|
|
||||||
|
private SendRtpItem sendRtpItem;
|
||||||
|
|
||||||
|
private MediaServerItem mediaServerItem;
|
||||||
|
|
||||||
|
public SendRtpItem getSendRtpItem() {
|
||||||
|
return sendRtpItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSendRtpItem(SendRtpItem sendRtpItem) {
|
||||||
|
this.sendRtpItem = sendRtpItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaServerItem getMediaServerItem() {
|
||||||
|
return mediaServerItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaServerItem(MediaServerItem mediaServerItem) {
|
||||||
|
this.mediaServerItem = mediaServerItem;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
package com.genersoft.iot.vmp.service.bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
|
public class WvpRedisMsg {
|
||||||
|
|
||||||
|
public static WvpRedisMsg getInstance(String fromId, String toId, String type, String cmd, String serial, String content){
|
||||||
|
WvpRedisMsg wvpRedisMsg = new WvpRedisMsg();
|
||||||
|
wvpRedisMsg.setFromId(fromId);
|
||||||
|
wvpRedisMsg.setToId(toId);
|
||||||
|
wvpRedisMsg.setType(type);
|
||||||
|
wvpRedisMsg.setCmd(cmd);
|
||||||
|
wvpRedisMsg.setSerial(serial);
|
||||||
|
wvpRedisMsg.setContent(content);
|
||||||
|
return wvpRedisMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String fromId;
|
||||||
|
|
||||||
|
private String toId;
|
||||||
|
/**
|
||||||
|
* req 请求, res 回复
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
private String cmd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息的ID
|
||||||
|
*/
|
||||||
|
private String serial;
|
||||||
|
private Object content;
|
||||||
|
|
||||||
|
private final static String requestTag = "req";
|
||||||
|
private final static String responseTag = "res";
|
||||||
|
|
||||||
|
public static WvpRedisMsg getRequestInstance(String fromId, String toId, String cmd, String serial, Object content) {
|
||||||
|
WvpRedisMsg wvpRedisMsg = new WvpRedisMsg();
|
||||||
|
wvpRedisMsg.setType(requestTag);
|
||||||
|
wvpRedisMsg.setFromId(fromId);
|
||||||
|
wvpRedisMsg.setToId(toId);
|
||||||
|
wvpRedisMsg.setCmd(cmd);
|
||||||
|
wvpRedisMsg.setSerial(serial);
|
||||||
|
wvpRedisMsg.setContent(content);
|
||||||
|
return wvpRedisMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WvpRedisMsg getResponseInstance() {
|
||||||
|
WvpRedisMsg wvpRedisMsg = new WvpRedisMsg();
|
||||||
|
wvpRedisMsg.setType(responseTag);
|
||||||
|
return wvpRedisMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WvpRedisMsg getResponseInstance(String fromId, String toId, String cmd, String serial, Object content) {
|
||||||
|
WvpRedisMsg wvpRedisMsg = new WvpRedisMsg();
|
||||||
|
wvpRedisMsg.setType(responseTag);
|
||||||
|
wvpRedisMsg.setFromId(fromId);
|
||||||
|
wvpRedisMsg.setToId(toId);
|
||||||
|
wvpRedisMsg.setCmd(cmd);
|
||||||
|
wvpRedisMsg.setSerial(serial);
|
||||||
|
wvpRedisMsg.setContent(content);
|
||||||
|
return wvpRedisMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isRequest(WvpRedisMsg wvpRedisMsg) {
|
||||||
|
return requestTag.equals(wvpRedisMsg.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSerial() {
|
||||||
|
return serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSerial(String serial) {
|
||||||
|
this.serial = serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFromId() {
|
||||||
|
return fromId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromId(String fromId) {
|
||||||
|
this.fromId = fromId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToId() {
|
||||||
|
return toId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToId(String toId) {
|
||||||
|
this.toId = toId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCmd() {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCmd(String cmd) {
|
||||||
|
this.cmd = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(Object content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.genersoft.iot.vmp.service.bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class WvpRedisMsgCmd {
|
||||||
|
|
||||||
|
public static final String GET_SEND_ITEM = "GetSendItem";
|
||||||
|
public static final String REQUEST_PUSH_STREAM = "RequestPushStream";
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,377 @@
|
|||||||
|
package com.genersoft.iot.vmp.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||||
|
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||||
|
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||||
|
import com.genersoft.iot.vmp.service.bean.*;
|
||||||
|
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||||
|
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||||
|
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.connection.Message;
|
||||||
|
import org.springframework.data.redis.connection.MessageListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.sip.InvalidArgumentException;
|
||||||
|
import javax.sip.SipException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听下级发送推送信息,并发送国标推流消息上级
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class RedisGbPlayMsgListener implements MessageListener {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(RedisGbPlayMsgListener.class);
|
||||||
|
|
||||||
|
public static final String WVP_PUSH_STREAM_KEY = "WVP_PUSH_STREAM";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流媒体不存在的错误玛
|
||||||
|
*/
|
||||||
|
public static final int ERROR_CODE_MEDIA_SERVER_NOT_FOUND = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 离线的错误玛
|
||||||
|
*/
|
||||||
|
public static final int ERROR_CODE_OFFLINE = -2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超时的错误玛
|
||||||
|
*/
|
||||||
|
public static final int ERROR_CODE_TIMEOUT = -3;
|
||||||
|
|
||||||
|
private Map<String, PlayMsgCallback> callbacks = new ConcurrentHashMap<>();
|
||||||
|
private Map<String, PlayMsgCallbackForStartSendRtpStream> callbacksForStartSendRtpStream = new ConcurrentHashMap<>();
|
||||||
|
private Map<String, PlayMsgErrorCallback> callbacksForError = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserSetting userSetting;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisUtil redis;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ZLMMediaListManager zlmMediaListManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMediaServerService mediaServerService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IRedisCatchStorage redisCatchStorage;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DynamicTask dynamicTask;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ZLMMediaListManager mediaListManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ZLMHttpHookSubscribe subscribe;
|
||||||
|
|
||||||
|
|
||||||
|
public interface PlayMsgCallback{
|
||||||
|
void handler(ResponseSendItemMsg responseSendItemMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface PlayMsgCallbackForStartSendRtpStream{
|
||||||
|
void handler(JSONObject jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface PlayMsgErrorCallback{
|
||||||
|
void handler(WVPResult wvpResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(Message message, byte[] bytes) {
|
||||||
|
JSONObject msgJSON = JSON.parseObject(message.getBody(), JSONObject.class);
|
||||||
|
WvpRedisMsg wvpRedisMsg = JSON.toJavaObject(msgJSON, WvpRedisMsg.class);
|
||||||
|
if (!userSetting.getServerId().equals(wvpRedisMsg.getToId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (WvpRedisMsg.isRequest(wvpRedisMsg)) {
|
||||||
|
logger.info("[收到REDIS通知] 请求: {}", new String(message.getBody()));
|
||||||
|
|
||||||
|
switch (wvpRedisMsg.getCmd()){
|
||||||
|
case WvpRedisMsgCmd.GET_SEND_ITEM:
|
||||||
|
RequestSendItemMsg content = JSON.toJavaObject((JSONObject)wvpRedisMsg.getContent(), RequestSendItemMsg.class);
|
||||||
|
requestSendItemMsgHand(content, wvpRedisMsg.getFromId(), wvpRedisMsg.getSerial());
|
||||||
|
break;
|
||||||
|
case WvpRedisMsgCmd.REQUEST_PUSH_STREAM:
|
||||||
|
RequestPushStreamMsg param = JSON.toJavaObject((JSONObject)wvpRedisMsg.getContent(), RequestPushStreamMsg.class);;
|
||||||
|
requestPushStreamMsgHand(param, wvpRedisMsg.getFromId(), wvpRedisMsg.getSerial());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}else {
|
||||||
|
logger.info("[收到REDIS通知] 回复: {}", new String(message.getBody()));
|
||||||
|
switch (wvpRedisMsg.getCmd()){
|
||||||
|
case WvpRedisMsgCmd.GET_SEND_ITEM:
|
||||||
|
|
||||||
|
WVPResult content = JSON.toJavaObject((JSONObject)wvpRedisMsg.getContent(), WVPResult.class);
|
||||||
|
|
||||||
|
String key = wvpRedisMsg.getSerial();
|
||||||
|
switch (content.getCode()) {
|
||||||
|
case 0:
|
||||||
|
ResponseSendItemMsg responseSendItemMsg =JSON.toJavaObject((JSONObject)content.getData(), ResponseSendItemMsg.class);
|
||||||
|
PlayMsgCallback playMsgCallback = callbacks.get(key);
|
||||||
|
if (playMsgCallback != null) {
|
||||||
|
callbacksForError.remove(key);
|
||||||
|
playMsgCallback.handler(responseSendItemMsg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ERROR_CODE_MEDIA_SERVER_NOT_FOUND:
|
||||||
|
case ERROR_CODE_OFFLINE:
|
||||||
|
case ERROR_CODE_TIMEOUT:
|
||||||
|
PlayMsgErrorCallback errorCallback = callbacksForError.get(key);
|
||||||
|
if (errorCallback != null) {
|
||||||
|
callbacks.remove(key);
|
||||||
|
errorCallback.handler(content);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WvpRedisMsgCmd.REQUEST_PUSH_STREAM:
|
||||||
|
WVPResult wvpResult = JSON.toJavaObject((JSONObject)wvpRedisMsg.getContent(), WVPResult.class);
|
||||||
|
String serial = wvpRedisMsg.getSerial();
|
||||||
|
switch (wvpResult.getCode()) {
|
||||||
|
case 0:
|
||||||
|
JSONObject jsonObject = (JSONObject)wvpResult.getData();
|
||||||
|
PlayMsgCallbackForStartSendRtpStream playMsgCallback = callbacksForStartSendRtpStream.get(serial);
|
||||||
|
if (playMsgCallback != null) {
|
||||||
|
callbacksForError.remove(serial);
|
||||||
|
playMsgCallback.handler(jsonObject);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ERROR_CODE_MEDIA_SERVER_NOT_FOUND:
|
||||||
|
case ERROR_CODE_OFFLINE:
|
||||||
|
case ERROR_CODE_TIMEOUT:
|
||||||
|
PlayMsgErrorCallback errorCallback = callbacksForError.get(serial);
|
||||||
|
if (errorCallback != null) {
|
||||||
|
callbacks.remove(serial);
|
||||||
|
errorCallback.handler(wvpResult);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理收到的请求推流的请求
|
||||||
|
*/
|
||||||
|
private void requestPushStreamMsgHand(RequestPushStreamMsg requestPushStreamMsg, String fromId, String serial) {
|
||||||
|
MediaServerItem mediaInfo = mediaServerService.getOne(requestPushStreamMsg.getMediaServerId());
|
||||||
|
if (mediaInfo == null) {
|
||||||
|
// TODO 回复错误
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String is_Udp = requestPushStreamMsg.isTcp() ? "0" : "1";
|
||||||
|
Map<String, Object> param = new HashMap<>();
|
||||||
|
param.put("vhost","__defaultVhost__");
|
||||||
|
param.put("app",requestPushStreamMsg.getApp());
|
||||||
|
param.put("stream",requestPushStreamMsg.getStream());
|
||||||
|
param.put("ssrc", requestPushStreamMsg.getSsrc());
|
||||||
|
param.put("dst_url",requestPushStreamMsg.getIp());
|
||||||
|
param.put("dst_port", requestPushStreamMsg.getPort());
|
||||||
|
param.put("is_udp", is_Udp);
|
||||||
|
param.put("src_port", requestPushStreamMsg.getSrcPort());
|
||||||
|
param.put("pt", requestPushStreamMsg.getPt());
|
||||||
|
param.put("use_ps", requestPushStreamMsg.isPs() ? "1" : "0");
|
||||||
|
param.put("only_audio", requestPushStreamMsg.isOnlyAudio() ? "1" : "0");
|
||||||
|
JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
|
||||||
|
// 回复消息
|
||||||
|
responsePushStream(jsonObject, fromId, serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void responsePushStream(JSONObject content, String toId, String serial) {
|
||||||
|
|
||||||
|
WVPResult<JSONObject> result = new WVPResult<>();
|
||||||
|
result.setCode(0);
|
||||||
|
result.setData(content);
|
||||||
|
|
||||||
|
WvpRedisMsg response = WvpRedisMsg.getResponseInstance(userSetting.getServerId(), toId,
|
||||||
|
WvpRedisMsgCmd.REQUEST_PUSH_STREAM, serial, result);
|
||||||
|
JSONObject jsonObject = (JSONObject)JSON.toJSON(response);
|
||||||
|
redis.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理收到的请求sendItem的请求
|
||||||
|
*/
|
||||||
|
private void requestSendItemMsgHand(RequestSendItemMsg content, String toId, String serial) {
|
||||||
|
MediaServerItem mediaServerItem = mediaServerService.getOne(content.getMediaServerId());
|
||||||
|
if (mediaServerItem == null) {
|
||||||
|
logger.info("[回复推流信息] 流媒体{}不存在 ", content.getMediaServerId());
|
||||||
|
|
||||||
|
WVPResult<SendRtpItem> result = new WVPResult<>();
|
||||||
|
result.setCode(ERROR_CODE_MEDIA_SERVER_NOT_FOUND);
|
||||||
|
result.setMsg("流媒体不存在");
|
||||||
|
|
||||||
|
WvpRedisMsg response = WvpRedisMsg.getResponseInstance(userSetting.getServerId(), toId,
|
||||||
|
WvpRedisMsgCmd.GET_SEND_ITEM, serial, result);
|
||||||
|
|
||||||
|
JSONObject jsonObject = (JSONObject)JSON.toJSON(response);
|
||||||
|
redis.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 确定流是否在线
|
||||||
|
boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, content.getApp(), content.getStream());
|
||||||
|
if (streamReady) {
|
||||||
|
logger.info("[回复推流信息] {}/{}", content.getApp(), content.getStream());
|
||||||
|
responseSendItem(mediaServerItem, content, toId, serial);
|
||||||
|
}else {
|
||||||
|
// 流已经离线
|
||||||
|
// 发送redis消息以使设备上线
|
||||||
|
logger.info("[ app={}, stream={} ]通道离线,发送redis信息控制设备开始推流",content.getApp(), content.getStream());
|
||||||
|
|
||||||
|
String taskKey = UUID.randomUUID().toString();
|
||||||
|
// 设置超时
|
||||||
|
dynamicTask.startDelay(taskKey, ()->{
|
||||||
|
logger.info("[ app={}, stream={} ] 等待设备开始推流超时", content.getApp(), content.getStream());
|
||||||
|
WVPResult<SendRtpItem> result = new WVPResult<>();
|
||||||
|
result.setCode(ERROR_CODE_TIMEOUT);
|
||||||
|
WvpRedisMsg response = WvpRedisMsg.getResponseInstance(
|
||||||
|
userSetting.getServerId(), toId, WvpRedisMsgCmd.GET_SEND_ITEM, serial, result
|
||||||
|
);
|
||||||
|
JSONObject jsonObject = (JSONObject)JSON.toJSON(response);
|
||||||
|
redis.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject);
|
||||||
|
}, userSetting.getPlatformPlayTimeout());
|
||||||
|
|
||||||
|
// 添加订阅
|
||||||
|
JSONObject subscribeKey = new JSONObject();
|
||||||
|
subscribeKey.put("app", content.getApp());
|
||||||
|
subscribeKey.put("stream", content.getStream());
|
||||||
|
subscribeKey.put("regist", true);
|
||||||
|
subscribeKey.put("schema", "rtmp");
|
||||||
|
subscribeKey.put("mediaServerId", mediaServerItem.getId());
|
||||||
|
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
||||||
|
(MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
||||||
|
dynamicTask.stop(taskKey);
|
||||||
|
responseSendItem(mediaServerItem, content, toId, serial);
|
||||||
|
});
|
||||||
|
|
||||||
|
MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(1, content.getApp(), content.getStream(),
|
||||||
|
content.getChannelId(), content.getPlatformId(), content.getPlatformName(), content.getServerId(),
|
||||||
|
content.getMediaServerId());
|
||||||
|
redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将获取到的sendItem发送出去
|
||||||
|
*/
|
||||||
|
private void responseSendItem(MediaServerItem mediaServerItem, RequestSendItemMsg content, String toId, String serial) {
|
||||||
|
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, content.getIp(),
|
||||||
|
content.getPort(), content.getSsrc(), content.getPlatformId(),
|
||||||
|
content.getApp(), content.getStream(), content.getChannelId(),
|
||||||
|
content.getTcp());
|
||||||
|
|
||||||
|
WVPResult<ResponseSendItemMsg> result = new WVPResult<>();
|
||||||
|
result.setCode(0);
|
||||||
|
ResponseSendItemMsg responseSendItemMsg = new ResponseSendItemMsg();
|
||||||
|
responseSendItemMsg.setSendRtpItem(sendRtpItem);
|
||||||
|
responseSendItemMsg.setMediaServerItem(mediaServerItem);
|
||||||
|
result.setData(responseSendItemMsg);
|
||||||
|
|
||||||
|
WvpRedisMsg response = WvpRedisMsg.getResponseInstance(
|
||||||
|
userSetting.getServerId(), toId, WvpRedisMsgCmd.GET_SEND_ITEM, serial, result
|
||||||
|
);
|
||||||
|
JSONObject jsonObject = (JSONObject)JSON.toJSON(response);
|
||||||
|
redis.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息要求下级生成推流信息
|
||||||
|
* @param serverId 下级服务ID
|
||||||
|
* @param app 应用名
|
||||||
|
* @param stream 流ID
|
||||||
|
* @param ip 目标IP
|
||||||
|
* @param port 目标端口
|
||||||
|
* @param ssrc ssrc
|
||||||
|
* @param platformId 平台国标编号
|
||||||
|
* @param channelId 通道ID
|
||||||
|
* @param isTcp 是否使用TCP
|
||||||
|
* @param callback 得到信息的回调
|
||||||
|
*/
|
||||||
|
public void sendMsg(String serverId, String mediaServerId, String app, String stream, String ip, int port, String ssrc,
|
||||||
|
String platformId, String channelId, boolean isTcp, String platformName, PlayMsgCallback callback, PlayMsgErrorCallback errorCallback) {
|
||||||
|
RequestSendItemMsg requestSendItemMsg = RequestSendItemMsg.getInstance(
|
||||||
|
serverId, mediaServerId, app, stream, ip, port, ssrc, platformId, channelId, isTcp, platformName);
|
||||||
|
requestSendItemMsg.setServerId(serverId);
|
||||||
|
String key = UUID.randomUUID().toString();
|
||||||
|
WvpRedisMsg redisMsg = WvpRedisMsg.getRequestInstance(userSetting.getServerId(), serverId, WvpRedisMsgCmd.GET_SEND_ITEM,
|
||||||
|
key, requestSendItemMsg);
|
||||||
|
|
||||||
|
JSONObject jsonObject = (JSONObject)JSON.toJSON(redisMsg);
|
||||||
|
logger.info("[请求推流SendItem] {}: {}", serverId, jsonObject);
|
||||||
|
callbacks.put(key, callback);
|
||||||
|
callbacksForError.put(key, errorCallback);
|
||||||
|
dynamicTask.startDelay(key, ()->{
|
||||||
|
callbacks.remove(key);
|
||||||
|
callbacksForError.remove(key);
|
||||||
|
WVPResult<Object> wvpResult = new WVPResult<>();
|
||||||
|
wvpResult.setCode(ERROR_CODE_TIMEOUT);
|
||||||
|
wvpResult.setMsg("timeout");
|
||||||
|
errorCallback.handler(wvpResult);
|
||||||
|
}, userSetting.getPlatformPlayTimeout());
|
||||||
|
redis.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送请求推流的消息
|
||||||
|
* @param param 推流参数
|
||||||
|
* @param callback 回调
|
||||||
|
*/
|
||||||
|
public void sendMsgForStartSendRtpStream(String serverId, RequestPushStreamMsg param, PlayMsgCallbackForStartSendRtpStream callback) {
|
||||||
|
String key = UUID.randomUUID().toString();
|
||||||
|
WvpRedisMsg redisMsg = WvpRedisMsg.getRequestInstance(userSetting.getServerId(), serverId,
|
||||||
|
WvpRedisMsgCmd.REQUEST_PUSH_STREAM, key, param);
|
||||||
|
|
||||||
|
JSONObject jsonObject = (JSONObject)JSON.toJSON(redisMsg);
|
||||||
|
logger.info("[REDIS 请求其他平台推流] {}: {}", serverId, jsonObject);
|
||||||
|
dynamicTask.startDelay(key, ()->{
|
||||||
|
callbacksForStartSendRtpStream.remove(key);
|
||||||
|
callbacksForError.remove(key);
|
||||||
|
}, userSetting.getPlatformPlayTimeout());
|
||||||
|
callbacksForStartSendRtpStream.put(key, callback);
|
||||||
|
callbacksForError.put(key, (wvpResult)->{
|
||||||
|
logger.info("[REDIS 请求其他平台推流] 失败: {}", wvpResult.getMsg());
|
||||||
|
callbacksForStartSendRtpStream.remove(key);
|
||||||
|
callbacksForError.remove(key);
|
||||||
|
});
|
||||||
|
redis.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject);
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.service.impl;
|
|||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
||||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -10,17 +11,23 @@ import org.springframework.data.redis.connection.Message;
|
|||||||
import org.springframework.data.redis.connection.MessageListener;
|
import org.springframework.data.redis.connection.MessageListener;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收来自redis的GPS更新通知
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class RedisGPSMsgListener implements MessageListener {
|
public class RedisGpsMsgListener implements MessageListener {
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(RedisGPSMsgListener.class);
|
private final static Logger logger = LoggerFactory.getLogger(RedisGpsMsgListener.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IRedisCatchStorage redisCatchStorage;
|
private IRedisCatchStorage redisCatchStorage;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(Message message, byte[] bytes) {
|
public void onMessage(@NotNull Message message, byte[] bytes) {
|
||||||
logger.info("收到来自REDIS的GPS通知: {}", new String(message.getBody()));
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("收到来自REDIS的GPS通知: {}", new String(message.getBody()));
|
||||||
|
}
|
||||||
GPSMsgInfo gpsMsgInfo = JSON.parseObject(message.getBody(), GPSMsgInfo.class);
|
GPSMsgInfo gpsMsgInfo = JSON.parseObject(message.getBody(), GPSMsgInfo.class);
|
||||||
redisCatchStorage.updateGpsMsgInfo(gpsMsgInfo);
|
redisCatchStorage.updateGpsMsgInfo(gpsMsgInfo);
|
||||||
}
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package com.genersoft.iot.vmp.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.AlarmChannelMessage;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
|
||||||
|
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||||
|
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.connection.Message;
|
||||||
|
import org.springframework.data.redis.connection.MessageListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lin
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class RedisStreamMsgListener implements MessageListener {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(RedisStreamMsgListener.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISIPCommander commander;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISIPCommanderForPlatform commanderForPlatform;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IVideoManagerStorage storage;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserSetting userSetting;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ZLMMediaListManager zlmMediaListManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(Message message, byte[] bytes) {
|
||||||
|
|
||||||
|
JSONObject steamMsgJson = JSON.parseObject(message.getBody(), JSONObject.class);
|
||||||
|
if (steamMsgJson == null) {
|
||||||
|
logger.warn("[REDIS的ALARM通知]消息解析失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String serverId = steamMsgJson.getString("serverId");
|
||||||
|
|
||||||
|
if (userSetting.getServerId().equals(serverId)) {
|
||||||
|
// 自己发送的消息忽略即可
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info("[REDIS通知] 流变化: {}", new String(message.getBody()));
|
||||||
|
String app = steamMsgJson.getString("app");
|
||||||
|
String stream = steamMsgJson.getString("stream");
|
||||||
|
boolean register = steamMsgJson.getBoolean("register");
|
||||||
|
String mediaServerId = steamMsgJson.getString("mediaServerId");
|
||||||
|
MediaItem mediaItem = new MediaItem();
|
||||||
|
mediaItem.setSeverId(serverId);
|
||||||
|
mediaItem.setApp(app);
|
||||||
|
mediaItem.setStream(stream);
|
||||||
|
mediaItem.setRegist(register);
|
||||||
|
mediaItem.setMediaServerId(mediaServerId);
|
||||||
|
mediaItem.setCreateStamp(System.currentTimeMillis()/1000);
|
||||||
|
mediaItem.setAliveSecond(0L);
|
||||||
|
mediaItem.setTotalReaderCount("0");
|
||||||
|
mediaItem.setOriginType(0);
|
||||||
|
mediaItem.setOriginTypeStr("0");
|
||||||
|
mediaItem.setOriginTypeStr("unknown");
|
||||||
|
|
||||||
|
zlmMediaListManager.addPush(mediaItem);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -107,6 +107,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
|
|||||||
streamPushItem.setStatus(true);
|
streamPushItem.setStatus(true);
|
||||||
streamPushItem.setStreamType("push");
|
streamPushItem.setStreamType("push");
|
||||||
streamPushItem.setVhost(item.getVhost());
|
streamPushItem.setVhost(item.getVhost());
|
||||||
|
streamPushItem.setServerId(item.getSeverId());
|
||||||
return streamPushItem;
|
return streamPushItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,6 +356,15 @@ public interface IVideoManagerStorage {
|
|||||||
int removeMedia(String app, String stream);
|
int removeMedia(String app, String stream);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取但个推流
|
||||||
|
* @param app
|
||||||
|
* @param stream
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
StreamPushItem getMedia(String app, String stream);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清空推流列表
|
* 清空推流列表
|
||||||
*/
|
*/
|
||||||
|
@ -14,9 +14,9 @@ import java.util.List;
|
|||||||
public interface StreamPushMapper {
|
public interface StreamPushMapper {
|
||||||
|
|
||||||
@Insert("INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
|
@Insert("INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
|
||||||
"createStamp, aliveSecond, mediaServerId) VALUES" +
|
"createStamp, aliveSecond, mediaServerId, serverId) VALUES" +
|
||||||
"('${app}', '${stream}', '${totalReaderCount}', '${originType}', '${originTypeStr}', " +
|
"('${app}', '${stream}', '${totalReaderCount}', '${originType}', '${originTypeStr}', " +
|
||||||
"'${createStamp}', '${aliveSecond}', '${mediaServerId}' )")
|
"'${createStamp}', '${aliveSecond}', '${mediaServerId}' , '${serverId}' )")
|
||||||
int add(StreamPushItem streamPushItem);
|
int add(StreamPushItem streamPushItem);
|
||||||
|
|
||||||
@Update("UPDATE stream_push " +
|
@Update("UPDATE stream_push " +
|
||||||
|
@ -587,11 +587,11 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
|
|||||||
String scanKey = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetting.getServerId() + "_*";
|
String scanKey = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetting.getServerId() + "_*";
|
||||||
List<GPSMsgInfo> result = new ArrayList<>();
|
List<GPSMsgInfo> result = new ArrayList<>();
|
||||||
List<Object> keys = redis.scan(scanKey);
|
List<Object> keys = redis.scan(scanKey);
|
||||||
for (int i = 0; i < keys.size(); i++) {
|
for (Object o : keys) {
|
||||||
String key = (String) keys.get(i);
|
String key = (String) o;
|
||||||
GPSMsgInfo gpsMsgInfo = (GPSMsgInfo) redis.get(key);
|
GPSMsgInfo gpsMsgInfo = (GPSMsgInfo) redis.get(key);
|
||||||
if (!gpsMsgInfo.isStored()) { // 只取没有存过得
|
if (!gpsMsgInfo.isStored()) { // 只取没有存过得
|
||||||
result.add((GPSMsgInfo)redis.get(key));
|
result.add((GPSMsgInfo) redis.get(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,7 +667,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
|
|||||||
@Override
|
@Override
|
||||||
public void sendStreamPushRequestedMsg(MessageForPushChannel msg) {
|
public void sendStreamPushRequestedMsg(MessageForPushChannel msg) {
|
||||||
String key = VideoManagerConstants.VM_MSG_STREAM_PUSH_REQUESTED;
|
String key = VideoManagerConstants.VM_MSG_STREAM_PUSH_REQUESTED;
|
||||||
logger.info("[redis 推流被请求通知] {}: {}-{}", key, msg.getApp(), msg.getStream());
|
logger.info("[redis 推流被请求通知] {}: {}/{}", key, msg.getApp(), msg.getStream());
|
||||||
redis.convertAndSend(key, (JSONObject)JSON.toJSON(msg));
|
redis.convertAndSend(key, (JSONObject)JSON.toJSON(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,6 +884,11 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
|
|||||||
return streamPushMapper.del(app, stream);
|
return streamPushMapper.del(app, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StreamPushItem getMedia(String app, String stream) {
|
||||||
|
return streamPushMapper.selectOne(app, stream);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearMediaList() {
|
public void clearMediaList() {
|
||||||
streamPushMapper.clear();
|
streamPushMapper.clear();
|
||||||
|
@ -7,11 +7,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
let webrtcPlayer = null;
|
||||||
export default {
|
export default {
|
||||||
name: 'rtcPlayer',
|
name: 'rtcPlayer',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
webrtcPlayer: null,
|
|
||||||
timer: null
|
timer: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -35,7 +35,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
play: function (url) {
|
play: function (url) {
|
||||||
this.webrtcPlayer = new ZLMRTCClient.Endpoint({
|
webrtcPlayer = new ZLMRTCClient.Endpoint({
|
||||||
element: document.getElementById('webRtcPlayerBox'),// video 标签
|
element: document.getElementById('webRtcPlayerBox'),// video 标签
|
||||||
debug: true,// 是否打印日志
|
debug: true,// 是否打印日志
|
||||||
zlmsdpUrl: url,//流地址
|
zlmsdpUrl: url,//流地址
|
||||||
@ -45,17 +45,17 @@ export default {
|
|||||||
videoEnable: false,
|
videoEnable: false,
|
||||||
recvOnly: true,
|
recvOnly: true,
|
||||||
})
|
})
|
||||||
this.webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,(e)=>{// ICE 协商出错
|
webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,(e)=>{// ICE 协商出错
|
||||||
console.error('ICE 协商出错')
|
console.error('ICE 协商出错')
|
||||||
this.eventcallbacK("ICE ERROR", "ICE 协商出错")
|
this.eventcallbacK("ICE ERROR", "ICE 协商出错")
|
||||||
});
|
});
|
||||||
|
|
||||||
this.webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,(e)=>{//获取到了远端流,可以播放
|
webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,(e)=>{//获取到了远端流,可以播放
|
||||||
console.error('播放成功',e.streams)
|
console.error('播放成功',e.streams)
|
||||||
this.eventcallbacK("playing", "播放成功")
|
this.eventcallbacK("playing", "播放成功")
|
||||||
});
|
});
|
||||||
|
|
||||||
this.webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,(e)=>{// offer anwser 交换失败
|
webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,(e)=>{// offer anwser 交换失败
|
||||||
console.error('offer anwser 交换失败',e)
|
console.error('offer anwser 交换失败',e)
|
||||||
this.eventcallbacK("OFFER ANSWER ERROR ", "offer anwser 交换失败")
|
this.eventcallbacK("OFFER ANSWER ERROR ", "offer anwser 交换失败")
|
||||||
if (e.code ==-400 && e.msg=="流不存在"){
|
if (e.code ==-400 && e.msg=="流不存在"){
|
||||||
@ -68,7 +68,7 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM,(s)=>{// 获取到了本地流
|
webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM,(s)=>{// 获取到了本地流
|
||||||
|
|
||||||
// document.getElementById('selfVideo').srcObject=s;
|
// document.getElementById('selfVideo').srcObject=s;
|
||||||
this.eventcallbacK("LOCAL STREAM", "获取到了本地流")
|
this.eventcallbacK("LOCAL STREAM", "获取到了本地流")
|
||||||
@ -76,9 +76,9 @@ export default {
|
|||||||
|
|
||||||
},
|
},
|
||||||
pause: function () {
|
pause: function () {
|
||||||
if (this.webrtcPlayer != null) {
|
if (webrtcPlayer != null) {
|
||||||
this.webrtcPlayer.close();
|
webrtcPlayer.close();
|
||||||
this.webrtcPlayer = null;
|
webrtcPlayer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user