648540858
3 years ago
52 changed files with 571 additions and 802 deletions
@ -0,0 +1,25 @@ |
|||
package com.genersoft.iot.vmp.gb28181.event.device; |
|||
|
|||
import org.springframework.context.ApplicationEvent; |
|||
|
|||
import javax.sip.TimeoutEvent; |
|||
|
|||
/** |
|||
* @author lin |
|||
*/ |
|||
public class RequestTimeoutEvent extends ApplicationEvent { |
|||
public RequestTimeoutEvent(Object source) { |
|||
super(source); |
|||
} |
|||
|
|||
|
|||
private TimeoutEvent timeoutEvent; |
|||
|
|||
public TimeoutEvent getTimeoutEvent() { |
|||
return timeoutEvent; |
|||
} |
|||
|
|||
public void setTimeoutEvent(TimeoutEvent timeoutEvent) { |
|||
this.timeoutEvent = timeoutEvent; |
|||
} |
|||
} |
@ -0,0 +1,41 @@ |
|||
package com.genersoft.iot.vmp.gb28181.event.device; |
|||
|
|||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
|||
import com.genersoft.iot.vmp.service.IDeviceService; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.context.ApplicationListener; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import javax.sip.ClientTransaction; |
|||
import javax.sip.address.SipURI; |
|||
import javax.sip.header.CallIdHeader; |
|||
import javax.sip.header.ToHeader; |
|||
import javax.sip.message.Request; |
|||
|
|||
/** |
|||
* @author lin |
|||
*/ |
|||
@Component |
|||
public class RequestTimeoutEventImpl implements ApplicationListener<RequestTimeoutEvent> { |
|||
|
|||
@Autowired |
|||
private IDeviceService deviceService; |
|||
|
|||
@Override |
|||
public void onApplicationEvent(RequestTimeoutEvent event) { |
|||
ClientTransaction clientTransaction = event.getTimeoutEvent().getClientTransaction(); |
|||
if (clientTransaction != null) { |
|||
Request request = clientTransaction.getRequest(); |
|||
if (request != null) { |
|||
String host = ((SipURI) request.getRequestURI()).getHost(); |
|||
int port = ((SipURI) request.getRequestURI()).getPort(); |
|||
Device device = deviceService.getDeviceByHostAndPort(host, port); |
|||
if (device == null) { |
|||
return; |
|||
} |
|||
deviceService.offline(device.getDeviceId()); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -1,63 +0,0 @@ |
|||
package com.genersoft.iot.vmp.gb28181.event.offline; |
|||
|
|||
import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener; |
|||
import com.genersoft.iot.vmp.conf.UserSetting; |
|||
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.listener.RedisMessageListenerContainer; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import com.genersoft.iot.vmp.common.VideoManagerConstants; |
|||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
|||
|
|||
/** |
|||
* @description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 |
|||
* @author: swwheihei |
|||
* @date: 2020年5月6日 上午11:35:46 |
|||
*/ |
|||
@Component |
|||
public class KeepliveTimeoutListener extends RedisKeyExpirationEventMessageListener { |
|||
|
|||
private Logger logger = LoggerFactory.getLogger(KeepliveTimeoutListener.class); |
|||
|
|||
@Autowired |
|||
private EventPublisher publisher; |
|||
|
|||
@Autowired |
|||
private UserSetting userSetting; |
|||
|
|||
public KeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer, UserSetting userSetting) { |
|||
super(listenerContainer, userSetting); |
|||
} |
|||
|
|||
@Override |
|||
public void init() { |
|||
if (!userSetting.getRedisConfig()) { |
|||
// 配置springboot默认Config为空,即不让应用去修改redis的默认配置,因为Redis服务出于安全会禁用CONFIG命令给远程用户使用
|
|||
setKeyspaceNotificationsConfigParameter(""); |
|||
} |
|||
super.init(); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 监听失效的key,key格式为keeplive_deviceId |
|||
* @param message |
|||
* @param pattern |
|||
*/ |
|||
@Override |
|||
public void onMessage(Message message, byte[] pattern) { |
|||
// 获取失效的key
|
|||
String expiredKey = message.toString(); |
|||
String KEEPLIVEKEY_PREFIX = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetting.getServerId() + "_"; |
|||
if(!expiredKey.startsWith(KEEPLIVEKEY_PREFIX)){ |
|||
logger.debug("收到redis过期监听,但开头不是"+KEEPLIVEKEY_PREFIX+",忽略"); |
|||
return; |
|||
} |
|||
|
|||
String deviceId = expiredKey.substring(KEEPLIVEKEY_PREFIX.length(),expiredKey.length()); |
|||
publisher.outlineEventPublish(deviceId, VideoManagerConstants.EVENT_OUTLINE_TIMEOUT); |
|||
} |
|||
} |
@ -1,40 +0,0 @@ |
|||
package com.genersoft.iot.vmp.gb28181.event.offline; |
|||
|
|||
import org.springframework.context.ApplicationEvent; |
|||
|
|||
/** |
|||
* @description: 离线事件类 |
|||
* @author: swwheihei |
|||
* @date: 2020年5月6日 上午11:33:13 |
|||
*/ |
|||
public class OfflineEvent extends ApplicationEvent { |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
public OfflineEvent(Object source) { |
|||
super(source); |
|||
} |
|||
|
|||
private String deviceId; |
|||
|
|||
private String from; |
|||
|
|||
public String getDeviceId() { |
|||
return deviceId; |
|||
} |
|||
|
|||
public void setDeviceId(String deviceId) { |
|||
this.deviceId = deviceId; |
|||
} |
|||
|
|||
public String getFrom() { |
|||
return from; |
|||
} |
|||
|
|||
public void setFrom(String from) { |
|||
this.from = from; |
|||
} |
|||
} |
@ -1,98 +0,0 @@ |
|||
package com.genersoft.iot.vmp.gb28181.event.offline; |
|||
|
|||
import com.genersoft.iot.vmp.conf.UserSetting; |
|||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
|||
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; |
|||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
|||
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
|||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
|||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
|||
import com.genersoft.iot.vmp.service.IMediaServerService; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.context.ApplicationListener; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import com.genersoft.iot.vmp.common.VideoManagerConstants; |
|||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
|||
import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @description: 离线事件监听器,监听到离线后,修改设备离在线状态。 设备离线有两个来源: |
|||
* 1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.RegisterRequestProcessor} |
|||
* 2、设备未知原因离线,心跳超时,{@link com.genersoft.iot.vmp.gb28181.event.offline.OfflineEventListener} |
|||
* @author: swwheihei |
|||
* @date: 2020年5月6日 下午1:51:23 |
|||
*/ |
|||
@Component |
|||
public class OfflineEventListener implements ApplicationListener<OfflineEvent> { |
|||
|
|||
private final static Logger logger = LoggerFactory.getLogger(OfflineEventListener.class); |
|||
|
|||
@Autowired |
|||
private IVideoManagerStorage storager; |
|||
|
|||
@Autowired |
|||
private VideoStreamSessionManager streamSession; |
|||
|
|||
@Autowired |
|||
private RedisUtil redis; |
|||
|
|||
@Autowired |
|||
private UserSetting userSetting; |
|||
|
|||
@Autowired |
|||
private EventPublisher eventPublisher; |
|||
|
|||
|
|||
@Autowired |
|||
private IMediaServerService mediaServerService; |
|||
|
|||
|
|||
@Autowired |
|||
private ZLMRTPServerFactory zlmrtpServerFactory; |
|||
|
|||
@Override |
|||
public void onApplicationEvent(OfflineEvent event) { |
|||
|
|||
logger.info("设备离线事件触发,deviceId:" + event.getDeviceId() + ",from:" + event.getFrom()); |
|||
|
|||
String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetting.getServerId() + "_" + event.getDeviceId(); |
|||
|
|||
switch (event.getFrom()) { |
|||
// 心跳超时触发的离线事件,说明redis中已删除,无需处理
|
|||
case VideoManagerConstants.EVENT_OUTLINE_TIMEOUT: |
|||
break; |
|||
// 设备主动注销触发的离线事件,需要删除redis中的超时监听
|
|||
case VideoManagerConstants.EVENT_OUTLINE_UNREGISTER: |
|||
redis.del(key); |
|||
break; |
|||
default: |
|||
boolean exist = redis.hasKey(key); |
|||
if (exist) { |
|||
redis.del(key); |
|||
} |
|||
} |
|||
|
|||
List<DeviceChannel> deviceChannelList = storager.queryOnlineChannelsByDeviceId(event.getDeviceId()); |
|||
eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.OFF); |
|||
// 处理离线监听
|
|||
storager.outline(event.getDeviceId()); |
|||
|
|||
// TODO 离线取消订阅
|
|||
|
|||
// 离线释放所有ssrc
|
|||
List<SsrcTransaction> ssrcTransactions = streamSession.getSsrcTransactionForAll(event.getDeviceId(), null, null, null); |
|||
if (ssrcTransactions != null && ssrcTransactions.size() > 0) { |
|||
for (SsrcTransaction ssrcTransaction : ssrcTransactions) { |
|||
mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); |
|||
mediaServerService.closeRTPServer(event.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); |
|||
streamSession.remove(event.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
@ -1,51 +0,0 @@ |
|||
package com.genersoft.iot.vmp.gb28181.event.online; |
|||
|
|||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|||
import org.springframework.context.ApplicationEvent; |
|||
|
|||
/** |
|||
* @description: 在线事件类 |
|||
* @author: swwheihei |
|||
* @date: 2020年5月6日 上午11:32:56 |
|||
*/ |
|||
public class OnlineEvent extends ApplicationEvent { |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
public OnlineEvent(Object source) { |
|||
super(source); |
|||
} |
|||
|
|||
private Device device; |
|||
|
|||
private String from; |
|||
|
|||
private int expires; |
|||
|
|||
public Device getDevice() { |
|||
return device; |
|||
} |
|||
|
|||
public void setDevice(Device device) { |
|||
this.device = device; |
|||
} |
|||
|
|||
public String getFrom() { |
|||
return from; |
|||
} |
|||
|
|||
public void setFrom(String from) { |
|||
this.from = from; |
|||
} |
|||
|
|||
public int getExpires() { |
|||
return expires; |
|||
} |
|||
|
|||
public void setExpires(int expires) { |
|||
this.expires = expires; |
|||
} |
|||
} |
@ -1,110 +0,0 @@ |
|||
package com.genersoft.iot.vmp.gb28181.event.online; |
|||
|
|||
import com.genersoft.iot.vmp.conf.SipConfig; |
|||
import com.genersoft.iot.vmp.conf.UserSetting; |
|||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
|||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
|||
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
|||
import com.genersoft.iot.vmp.service.IDeviceService; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.context.ApplicationListener; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import com.genersoft.iot.vmp.common.VideoManagerConstants; |
|||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
|||
import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
|||
|
|||
import java.text.SimpleDateFormat; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @description: 在线事件监听器,监听到离线后,修改设备离在线状态。 设备在线有两个来源: |
|||
* 1、设备主动注销,发送注销指令 |
|||
* 2、设备未知原因离线,心跳超时 |
|||
* @author: swwheihei |
|||
* @date: 2020年5月6日 下午1:51:23 |
|||
*/ |
|||
@Component |
|||
public class OnlineEventListener implements ApplicationListener<OnlineEvent> { |
|||
|
|||
private final static Logger logger = LoggerFactory.getLogger(OnlineEventListener.class); |
|||
|
|||
@Autowired |
|||
private IVideoManagerStorage storager; |
|||
|
|||
@Autowired |
|||
private IDeviceService deviceService; |
|||
|
|||
@Autowired |
|||
private RedisUtil redis; |
|||
|
|||
@Autowired |
|||
private SipConfig sipConfig; |
|||
|
|||
@Autowired |
|||
private UserSetting userSetting; |
|||
|
|||
@Autowired |
|||
private EventPublisher eventPublisher; |
|||
|
|||
@Autowired |
|||
private SIPCommander cmder; |
|||
|
|||
|
|||
private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
|||
|
|||
@Override |
|||
public void onApplicationEvent(OnlineEvent event) { |
|||
|
|||
logger.info("设备上线事件触发,deviceId:" + event.getDevice().getDeviceId() + ",from:" + event.getFrom()); |
|||
Device device = event.getDevice(); |
|||
if (device == null) { |
|||
return; |
|||
} |
|||
String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetting.getServerId() + "_" + event.getDevice().getDeviceId(); |
|||
Device deviceInStore = storager.queryVideoDevice(device.getDeviceId()); |
|||
device.setOnline(1); |
|||
switch (event.getFrom()) { |
|||
// 注册时触发的在线事件,先在redis中增加超时超时监听
|
|||
case VideoManagerConstants.EVENT_ONLINE_REGISTER: |
|||
// 超时时间
|
|||
redis.set(key, event.getDevice().getDeviceId(), sipConfig.getKeepaliveTimeOut()); |
|||
device.setRegisterTime(format.format(System.currentTimeMillis())); |
|||
if (deviceInStore == null) { //第一次上线
|
|||
logger.info("[{}] 首次注册,查询设备信息以及通道信息", device.getDeviceId()); |
|||
cmder.deviceInfoQuery(device); |
|||
deviceService.sync(device); |
|||
} |
|||
break; |
|||
// 设备主动发送心跳触发的在线事件
|
|||
case VideoManagerConstants.EVENT_ONLINE_KEEPLIVE: |
|||
boolean exist = redis.hasKey(key); |
|||
// 先判断是否还存在,当设备先心跳超时后又发送心跳时,redis没有监听,需要增加
|
|||
if (!exist) { |
|||
redis.set(key, event.getDevice().getDeviceId(), sipConfig.getKeepaliveTimeOut()); |
|||
} else { |
|||
redis.expire(key, sipConfig.getKeepaliveTimeOut()); |
|||
} |
|||
device.setKeepaliveTime(format.format(System.currentTimeMillis())); |
|||
break; |
|||
// 设备主动发送消息触发的在线事件
|
|||
case VideoManagerConstants.EVENT_ONLINE_MESSAGE: |
|||
|
|||
break; |
|||
} |
|||
// 处理上线监听
|
|||
storager.updateDevice(device); |
|||
// 上线添加订阅
|
|||
if (device.getSubscribeCycleForCatalog() > 0) { |
|||
// 查询在线设备那些开启了订阅,为设备开启定时的目录订阅
|
|||
deviceService.addCatalogSubscribe(device); |
|||
} |
|||
if (device.getSubscribeCycleForMobilePosition() > 0) { |
|||
deviceService.addMobilePositionSubscribe(device); |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue