Commit ab81136765f1b641223b982b2baef13e06307fe4
1 parent
9b1af8ef
优化适配zlm的hook保活
Showing
20 changed files
with
440 additions
and
78 deletions
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
| 1 | package com.genersoft.iot.vmp.gb28181; | 1 | package com.genersoft.iot.vmp.gb28181; |
| 2 | 2 | ||
| 3 | import com.genersoft.iot.vmp.conf.SipConfig; | 3 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 4 | -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | ||
| 5 | import com.genersoft.iot.vmp.gb28181.transmit.ISIPProcessorObserver; | 4 | import com.genersoft.iot.vmp.gb28181.transmit.ISIPProcessorObserver; |
| 6 | -import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; | ||
| 7 | import gov.nist.javax.sip.SipProviderImpl; | 5 | import gov.nist.javax.sip.SipProviderImpl; |
| 8 | import gov.nist.javax.sip.SipStackImpl; | 6 | import gov.nist.javax.sip.SipStackImpl; |
| 9 | import org.slf4j.Logger; | 7 | import org.slf4j.Logger; |
src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
| @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent; | @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent; | ||
| 5 | import com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire.PlatformKeepaliveExpireEvent; | 5 | import com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire.PlatformKeepaliveExpireEvent; |
| 6 | import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformNotRegisterEvent; | 6 | import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformNotRegisterEvent; |
| 7 | import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent; | 7 | import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent; |
| 8 | +import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent; | ||
| 8 | import org.springframework.beans.factory.annotation.Autowired; | 9 | import org.springframework.beans.factory.annotation.Autowired; |
| 9 | import org.springframework.context.ApplicationEventPublisher; | 10 | import org.springframework.context.ApplicationEventPublisher; |
| 10 | import org.springframework.stereotype.Component; | 11 | import org.springframework.stereotype.Component; |
| @@ -73,5 +74,10 @@ public class EventPublisher { | @@ -73,5 +74,10 @@ public class EventPublisher { | ||
| 73 | outEvent.setMediaServerId(mediaServerId); | 74 | outEvent.setMediaServerId(mediaServerId); |
| 74 | applicationEventPublisher.publishEvent(outEvent); | 75 | applicationEventPublisher.publishEvent(outEvent); |
| 75 | } | 76 | } |
| 76 | - | 77 | + |
| 78 | + public void zlmOnlineEventPublish(String mediaServerId) { | ||
| 79 | + ZLMOnlineEvent outEvent = new ZLMOnlineEvent(this); | ||
| 80 | + outEvent.setMediaServerId(mediaServerId); | ||
| 81 | + applicationEventPublisher.publishEvent(outEvent); | ||
| 82 | + } | ||
| 77 | } | 83 | } |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| @@ -179,29 +179,33 @@ public class ZLMHttpHookListener { | @@ -179,29 +179,33 @@ public class ZLMHttpHookListener { | ||
| 179 | public ResponseEntity<String> onPublish(@RequestBody JSONObject json) { | 179 | public ResponseEntity<String> onPublish(@RequestBody JSONObject json) { |
| 180 | 180 | ||
| 181 | logger.debug("[ ZLM HOOK ]on_publish API调用,参数:" + json.toString()); | 181 | logger.debug("[ ZLM HOOK ]on_publish API调用,参数:" + json.toString()); |
| 182 | - | 182 | + JSONObject ret = new JSONObject(); |
| 183 | + ret.put("code", 0); | ||
| 184 | + ret.put("msg", "success"); | ||
| 185 | + ret.put("enableHls", true); | ||
| 186 | + ret.put("enableMP4", userSetup.isRecordPushLive()); | ||
| 183 | String mediaServerId = json.getString("mediaServerId"); | 187 | String mediaServerId = json.getString("mediaServerId"); |
| 184 | ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); | 188 | ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); |
| 185 | if (subscribe != null) { | 189 | if (subscribe != null) { |
| 186 | MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); | 190 | MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); |
| 187 | if (mediaInfo != null) { | 191 | if (mediaInfo != null) { |
| 188 | subscribe.response(mediaInfo, json); | 192 | subscribe.response(mediaInfo, json); |
| 193 | + }else { | ||
| 194 | + ret.put("code", 1); | ||
| 195 | + ret.put("msg", "zlm not register"); | ||
| 189 | } | 196 | } |
| 190 | } | 197 | } |
| 191 | String app = json.getString("app"); | 198 | String app = json.getString("app"); |
| 192 | String stream = json.getString("stream"); | 199 | String stream = json.getString("stream"); |
| 193 | StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(stream); | 200 | StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(stream); |
| 194 | - JSONObject ret = new JSONObject(); | 201 | + |
| 195 | // 录像回放时不进行录像下载 | 202 | // 录像回放时不进行录像下载 |
| 196 | if (streamInfo != null) { | 203 | if (streamInfo != null) { |
| 197 | ret.put("enableMP4", false); | 204 | ret.put("enableMP4", false); |
| 198 | }else { | 205 | }else { |
| 199 | ret.put("enableMP4", userSetup.isRecordPushLive()); | 206 | ret.put("enableMP4", userSetup.isRecordPushLive()); |
| 200 | } | 207 | } |
| 201 | - ret.put("code", 0); | ||
| 202 | - ret.put("msg", "success"); | ||
| 203 | - ret.put("enableHls", true); | ||
| 204 | - ret.put("enableMP4", userSetup.isRecordPushLive()); | 208 | + |
| 205 | return new ResponseEntity<String>(ret.toString(), HttpStatus.OK); | 209 | return new ResponseEntity<String>(ret.toString(), HttpStatus.OK); |
| 206 | } | 210 | } |
| 207 | 211 | ||
| @@ -340,37 +344,38 @@ public class ZLMHttpHookListener { | @@ -340,37 +344,38 @@ public class ZLMHttpHookListener { | ||
| 340 | if (!"rtp".equals(app)){ | 344 | if (!"rtp".equals(app)){ |
| 341 | String type = OriginType.values()[item.getOriginType()].getType(); | 345 | String type = OriginType.values()[item.getOriginType()].getType(); |
| 342 | MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); | 346 | MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); |
| 343 | - if (regist) { | ||
| 344 | - StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, streamId, tracks); | ||
| 345 | - redisCatchStorage.addStream(mediaServerItem, type, app, streamId, streamInfo); | ||
| 346 | - if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal() | ||
| 347 | - || item.getOriginType() == OriginType.RTMP_PUSH.ordinal() | ||
| 348 | - || item.getOriginType() == OriginType.RTC_PUSH.ordinal() ) { | ||
| 349 | - zlmMediaListManager.addPush(item); | ||
| 350 | - } | ||
| 351 | - }else { | ||
| 352 | - // 兼容流注销时类型错误的问题,等zlm更新后删除 | ||
| 353 | - StreamPushItem streamPushItem = streamPushService.getPush(app, streamId); | ||
| 354 | - if (streamPushItem != null) { | ||
| 355 | - type = "PUSH"; | 347 | + if (mediaServerItem != null){ |
| 348 | + if (regist) { | ||
| 349 | + StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, streamId, tracks); | ||
| 350 | + redisCatchStorage.addStream(mediaServerItem, type, app, streamId, streamInfo); | ||
| 351 | + if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal() | ||
| 352 | + || item.getOriginType() == OriginType.RTMP_PUSH.ordinal() | ||
| 353 | + || item.getOriginType() == OriginType.RTC_PUSH.ordinal() ) { | ||
| 354 | + zlmMediaListManager.addPush(item); | ||
| 355 | + } | ||
| 356 | }else { | 356 | }else { |
| 357 | - StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(app, streamId); | ||
| 358 | - if (streamProxyByAppAndStream != null) { | ||
| 359 | - type = "PULL"; | 357 | + // 兼容流注销时类型错误的问题,等zlm更新后删除 |
| 358 | + StreamPushItem streamPushItem = streamPushService.getPush(app, streamId); | ||
| 359 | + if (streamPushItem != null) { | ||
| 360 | + type = "PUSH"; | ||
| 361 | + }else { | ||
| 362 | + StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(app, streamId); | ||
| 363 | + if (streamProxyByAppAndStream != null) { | ||
| 364 | + type = "PULL"; | ||
| 365 | + } | ||
| 360 | } | 366 | } |
| 367 | + zlmMediaListManager.removeMedia(app, streamId); | ||
| 368 | + redisCatchStorage.removeStream(mediaServerItem.getId(), type, app, streamId); | ||
| 361 | } | 369 | } |
| 362 | - zlmMediaListManager.removeMedia(app, streamId); | ||
| 363 | - redisCatchStorage.removeStream(mediaServerItem, type, app, streamId); | 370 | + // 发送流变化redis消息 |
| 371 | + JSONObject jsonObject = new JSONObject(); | ||
| 372 | + jsonObject.put("serverId", userSetup.getServerId()); | ||
| 373 | + jsonObject.put("app", app); | ||
| 374 | + jsonObject.put("stream", streamId); | ||
| 375 | + jsonObject.put("register", regist); | ||
| 376 | + jsonObject.put("mediaServerId", mediaServerId); | ||
| 377 | + redisCatchStorage.sendStreamChangeMsg(type, jsonObject); | ||
| 364 | } | 378 | } |
| 365 | - | ||
| 366 | - // 发送流变化redis消息 | ||
| 367 | - JSONObject jsonObject = new JSONObject(); | ||
| 368 | - jsonObject.put("serverId", userSetup.getServerId()); | ||
| 369 | - jsonObject.put("app", app); | ||
| 370 | - jsonObject.put("stream", streamId); | ||
| 371 | - jsonObject.put("register", regist); | ||
| 372 | - jsonObject.put("mediaServerId", mediaServerId); | ||
| 373 | - redisCatchStorage.sendStreamChangeMsg(type, jsonObject); | ||
| 374 | } | 379 | } |
| 375 | } | 380 | } |
| 376 | } | 381 | } |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
| @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON; | @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON; | ||
| 4 | import com.alibaba.fastjson.JSONArray; | 4 | import com.alibaba.fastjson.JSONArray; |
| 5 | import com.alibaba.fastjson.JSONObject; | 5 | import com.alibaba.fastjson.JSONObject; |
| 6 | import com.genersoft.iot.vmp.conf.MediaConfig; | 6 | import com.genersoft.iot.vmp.conf.MediaConfig; |
| 7 | +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | ||
| 7 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | 8 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 8 | import com.genersoft.iot.vmp.service.IMediaServerService; | 9 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 9 | import com.genersoft.iot.vmp.service.IStreamProxyService; | 10 | import com.genersoft.iot.vmp.service.IStreamProxyService; |
| @@ -17,6 +18,7 @@ import org.springframework.core.annotation.Order; | @@ -17,6 +18,7 @@ import org.springframework.core.annotation.Order; | ||
| 17 | import org.springframework.scheduling.annotation.Async; | 18 | import org.springframework.scheduling.annotation.Async; |
| 18 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | 19 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| 19 | import org.springframework.stereotype.Component; | 20 | import org.springframework.stereotype.Component; |
| 21 | +import org.springframework.util.StringUtils; | ||
| 20 | 22 | ||
| 21 | import java.util.*; | 23 | import java.util.*; |
| 22 | 24 | ||
| @@ -38,6 +40,9 @@ public class ZLMRunner implements CommandLineRunner { | @@ -38,6 +40,9 @@ public class ZLMRunner implements CommandLineRunner { | ||
| 38 | private IStreamProxyService streamProxyService; | 40 | private IStreamProxyService streamProxyService; |
| 39 | 41 | ||
| 40 | @Autowired | 42 | @Autowired |
| 43 | + private EventPublisher publisher; | ||
| 44 | + | ||
| 45 | + @Autowired | ||
| 41 | private IMediaServerService mediaServerService; | 46 | private IMediaServerService mediaServerService; |
| 42 | 47 | ||
| 43 | @Autowired | 48 | @Autowired |
| @@ -117,7 +122,7 @@ public class ZLMRunner implements CommandLineRunner { | @@ -117,7 +122,7 @@ public class ZLMRunner implements CommandLineRunner { | ||
| 117 | 122 | ||
| 118 | @Async | 123 | @Async |
| 119 | public void connectZlmServer(MediaServerItem mediaServerItem){ | 124 | public void connectZlmServer(MediaServerItem mediaServerItem){ |
| 120 | - ZLMServerConfig zlmServerConfig = getMediaServerConfig(mediaServerItem); | 125 | + ZLMServerConfig zlmServerConfig = getMediaServerConfig(mediaServerItem, 1); |
| 121 | if (zlmServerConfig != null) { | 126 | if (zlmServerConfig != null) { |
| 122 | zlmServerConfig.setIp(mediaServerItem.getIp()); | 127 | zlmServerConfig.setIp(mediaServerItem.getIp()); |
| 123 | zlmServerConfig.setHttpPort(mediaServerItem.getHttpPort()); | 128 | zlmServerConfig.setHttpPort(mediaServerItem.getHttpPort()); |
| @@ -126,7 +131,7 @@ public class ZLMRunner implements CommandLineRunner { | @@ -126,7 +131,7 @@ public class ZLMRunner implements CommandLineRunner { | ||
| 126 | } | 131 | } |
| 127 | } | 132 | } |
| 128 | 133 | ||
| 129 | - public ZLMServerConfig getMediaServerConfig(MediaServerItem mediaServerItem) { | 134 | + public ZLMServerConfig getMediaServerConfig(MediaServerItem mediaServerItem, int index) { |
| 130 | if (startGetMedia == null) { return null;} | 135 | if (startGetMedia == null) { return null;} |
| 131 | if (!mediaServerItem.isDefaultServer() && mediaServerService.getOne(mediaServerItem.getId()) == null) { | 136 | if (!mediaServerItem.isDefaultServer() && mediaServerService.getOne(mediaServerItem.getId()) == null) { |
| 132 | return null; | 137 | return null; |
| @@ -143,14 +148,19 @@ public class ZLMRunner implements CommandLineRunner { | @@ -143,14 +148,19 @@ public class ZLMRunner implements CommandLineRunner { | ||
| 143 | ZLMServerConfig.setIp(mediaServerItem.getIp()); | 148 | ZLMServerConfig.setIp(mediaServerItem.getIp()); |
| 144 | } | 149 | } |
| 145 | } else { | 150 | } else { |
| 146 | - logger.error("[ {} ]-[ {}:{} ]主动连接失败失败, 2s后重试", | ||
| 147 | - mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); | 151 | + logger.error("[ {} ]-[ {}:{} ]第{}次主动连接失败, 2s后重试", |
| 152 | + mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort(), index); | ||
| 153 | + if (index == 1 && !StringUtils.isEmpty(mediaServerItem.getId())) { | ||
| 154 | + logger.info("[ {} ]-[ {}:{} ]第{}次主动连接失败, 开始清理相关资源", | ||
| 155 | + mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort(), index); | ||
| 156 | + publisher.zlmOfflineEventPublish(mediaServerItem.getId()); | ||
| 157 | + } | ||
| 148 | try { | 158 | try { |
| 149 | Thread.sleep(2000); | 159 | Thread.sleep(2000); |
| 150 | } catch (InterruptedException e) { | 160 | } catch (InterruptedException e) { |
| 151 | e.printStackTrace(); | 161 | e.printStackTrace(); |
| 152 | } | 162 | } |
| 153 | - ZLMServerConfig = getMediaServerConfig(mediaServerItem); | 163 | + ZLMServerConfig = getMediaServerConfig(mediaServerItem, index += 1); |
| 154 | } | 164 | } |
| 155 | return ZLMServerConfig; | 165 | return ZLMServerConfig; |
| 156 | 166 |
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMKeepliveTimeoutListener.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.media.zlm.event; | ||
| 2 | + | ||
| 3 | +import com.genersoft.iot.vmp.common.VideoManagerConstants; | ||
| 4 | +import com.genersoft.iot.vmp.conf.UserSetup; | ||
| 5 | +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | ||
| 6 | +import org.slf4j.Logger; | ||
| 7 | +import org.slf4j.LoggerFactory; | ||
| 8 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 9 | +import org.springframework.data.redis.connection.Message; | ||
| 10 | +import org.springframework.data.redis.listener.KeyExpirationEventMessageListener; | ||
| 11 | +import org.springframework.data.redis.listener.RedisMessageListenerContainer; | ||
| 12 | +import org.springframework.stereotype.Component; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * @description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 | ||
| 16 | + * @author: swwheihei | ||
| 17 | + * @date: 2020年5月6日 上午11:35:46 | ||
| 18 | + */ | ||
| 19 | +@Component | ||
| 20 | +public class ZLMKeepliveTimeoutListener extends KeyExpirationEventMessageListener { | ||
| 21 | + | ||
| 22 | + private Logger logger = LoggerFactory.getLogger(ZLMKeepliveTimeoutListener.class); | ||
| 23 | + | ||
| 24 | + @Autowired | ||
| 25 | + private EventPublisher publisher; | ||
| 26 | + | ||
| 27 | + @Autowired | ||
| 28 | + private UserSetup userSetup; | ||
| 29 | + | ||
| 30 | + public ZLMKeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer) { | ||
| 31 | + super(listenerContainer); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * 监听失效的key,key格式为keeplive_deviceId | ||
| 36 | + * @param message | ||
| 37 | + * @param pattern | ||
| 38 | + */ | ||
| 39 | + @Override | ||
| 40 | + public void onMessage(Message message, byte[] pattern) { | ||
| 41 | + // 获取失效的key | ||
| 42 | + String expiredKey = message.toString(); | ||
| 43 | + String KEEPLIVEKEY_PREFIX = VideoManagerConstants.MEDIA_SERVER_KEEPALIVE_PREFIX + userSetup.getServerId() + "_"; | ||
| 44 | + if(!expiredKey.startsWith(KEEPLIVEKEY_PREFIX)){ | ||
| 45 | + return; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + String mediaServerId = expiredKey.substring(KEEPLIVEKEY_PREFIX.length(),expiredKey.length()); | ||
| 49 | + | ||
| 50 | + publisher.zlmOfflineEventPublish(mediaServerId); | ||
| 51 | + } | ||
| 52 | +} |
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOfflineEvent.java
0 → 100644
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOfflineEventListener.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.media.zlm.event; | ||
| 2 | + | ||
| 3 | +import com.genersoft.iot.vmp.conf.UserSetup; | ||
| 4 | +import com.genersoft.iot.vmp.service.IMediaServerService; | ||
| 5 | +import com.genersoft.iot.vmp.service.IStreamProxyService; | ||
| 6 | +import com.genersoft.iot.vmp.service.IStreamPushService; | ||
| 7 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | ||
| 8 | +import com.genersoft.iot.vmp.utils.redis.RedisUtil; | ||
| 9 | +import org.slf4j.Logger; | ||
| 10 | +import org.slf4j.LoggerFactory; | ||
| 11 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 12 | +import org.springframework.context.ApplicationListener; | ||
| 13 | +import org.springframework.stereotype.Component; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * | ||
| 17 | + */ | ||
| 18 | +@Component | ||
| 19 | +public class ZLMOfflineEventListener implements ApplicationListener<ZLMOfflineEvent> { | ||
| 20 | + | ||
| 21 | + private final static Logger logger = LoggerFactory.getLogger(ZLMOfflineEventListener.class); | ||
| 22 | + | ||
| 23 | + @Autowired | ||
| 24 | + private IMediaServerService mediaServerService; | ||
| 25 | + | ||
| 26 | + @Autowired | ||
| 27 | + private IStreamPushService streamPushService; | ||
| 28 | + | ||
| 29 | + @Autowired | ||
| 30 | + private IStreamProxyService streamProxyService; | ||
| 31 | + | ||
| 32 | + @Override | ||
| 33 | + public void onApplicationEvent(ZLMOfflineEvent event) { | ||
| 34 | + | ||
| 35 | + if (logger.isDebugEnabled()) { | ||
| 36 | + logger.debug("ZLM离线事件触发,ID:" + event.getMediaServerId()); | ||
| 37 | + } | ||
| 38 | + // 处理ZLM离线 | ||
| 39 | + mediaServerService.zlmServerOffline(event.getMediaServerId()); | ||
| 40 | + streamProxyService.zlmServerOffline(event.getMediaServerId()); | ||
| 41 | + streamPushService.zlmServerOffline(event.getMediaServerId()); | ||
| 42 | + // TODO 处理对国标的影响 | ||
| 43 | + } | ||
| 44 | +} |
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOnlineEvent.java
0 → 100644
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOnlineEventListener.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.media.zlm.event; | ||
| 2 | + | ||
| 3 | +import com.genersoft.iot.vmp.conf.SipConfig; | ||
| 4 | +import com.genersoft.iot.vmp.conf.UserSetup; | ||
| 5 | +import com.genersoft.iot.vmp.service.IMediaServerService; | ||
| 6 | +import com.genersoft.iot.vmp.service.IStreamProxyService; | ||
| 7 | +import com.genersoft.iot.vmp.service.IStreamPushService; | ||
| 8 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | ||
| 9 | +import com.genersoft.iot.vmp.utils.redis.RedisUtil; | ||
| 10 | +import org.slf4j.Logger; | ||
| 11 | +import org.slf4j.LoggerFactory; | ||
| 12 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 13 | +import org.springframework.context.ApplicationListener; | ||
| 14 | +import org.springframework.stereotype.Component; | ||
| 15 | + | ||
| 16 | +import java.text.SimpleDateFormat; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * @description: 在线事件监听器,监听到离线后,修改设备离在线状态。 设备在线有两个来源: | ||
| 20 | + * 1、设备主动注销,发送注销指令 | ||
| 21 | + * 2、设备未知原因离线,心跳超时 | ||
| 22 | + * @author: swwheihei | ||
| 23 | + * @date: 2020年5月6日 下午1:51:23 | ||
| 24 | + */ | ||
| 25 | +@Component | ||
| 26 | +public class ZLMOnlineEventListener implements ApplicationListener<ZLMOnlineEvent> { | ||
| 27 | + | ||
| 28 | + private final static Logger logger = LoggerFactory.getLogger(ZLMOnlineEventListener.class); | ||
| 29 | + | ||
| 30 | + @Autowired | ||
| 31 | + private IVideoManagerStorager storager; | ||
| 32 | + | ||
| 33 | + @Autowired | ||
| 34 | + private RedisUtil redis; | ||
| 35 | + | ||
| 36 | + @Autowired | ||
| 37 | + private SipConfig sipConfig; | ||
| 38 | + | ||
| 39 | + @Autowired | ||
| 40 | + private UserSetup userSetup; | ||
| 41 | + | ||
| 42 | + @Autowired | ||
| 43 | + private IMediaServerService mediaServerService; | ||
| 44 | + | ||
| 45 | + @Autowired | ||
| 46 | + private IStreamPushService streamPushService; | ||
| 47 | + | ||
| 48 | + @Autowired | ||
| 49 | + private IStreamProxyService streamProxyService; | ||
| 50 | + | ||
| 51 | + private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | ||
| 52 | + | ||
| 53 | + @Override | ||
| 54 | + public void onApplicationEvent(ZLMOnlineEvent event) { | ||
| 55 | + | ||
| 56 | + if (logger.isDebugEnabled()) { | ||
| 57 | + logger.debug("ZLM上线事件触发,ID:" + event.getMediaServerId()); | ||
| 58 | + } | ||
| 59 | + streamPushService.zlmServerOnline(event.getMediaServerId()); | ||
| 60 | + streamProxyService.zlmServerOnline(event.getMediaServerId()); | ||
| 61 | + | ||
| 62 | + | ||
| 63 | + | ||
| 64 | + } | ||
| 65 | +} |
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
| @@ -78,10 +78,10 @@ public interface IStreamProxyService { | @@ -78,10 +78,10 @@ public interface IStreamProxyService { | ||
| 78 | 78 | ||
| 79 | /** | 79 | /** |
| 80 | * 新的节点加入 | 80 | * 新的节点加入 |
| 81 | - * @param zlmServerConfig | 81 | + * @param mediaServerId |
| 82 | * @return | 82 | * @return |
| 83 | */ | 83 | */ |
| 84 | - void zlmServerOnline(ZLMServerConfig zlmServerConfig); | 84 | + void zlmServerOnline(String mediaServerId); |
| 85 | 85 | ||
| 86 | /** | 86 | /** |
| 87 | * 节点离线 | 87 | * 节点离线 |
| @@ -89,4 +89,6 @@ public interface IStreamProxyService { | @@ -89,4 +89,6 @@ public interface IStreamProxyService { | ||
| 89 | * @return | 89 | * @return |
| 90 | */ | 90 | */ |
| 91 | void zlmServerOffline(String mediaServerId); | 91 | void zlmServerOffline(String mediaServerId); |
| 92 | + | ||
| 93 | + void clean(); | ||
| 92 | } | 94 | } |
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
| @@ -34,6 +34,7 @@ public interface IStreamPushService { | @@ -34,6 +34,7 @@ public interface IStreamPushService { | ||
| 34 | * @return | 34 | * @return |
| 35 | */ | 35 | */ |
| 36 | PageInfo<StreamPushItem> getPushList(Integer page, Integer count); | 36 | PageInfo<StreamPushItem> getPushList(Integer page, Integer count); |
| 37 | + List<StreamPushItem> getPushList(String mediaSererId); | ||
| 37 | 38 | ||
| 38 | StreamPushItem transform(MediaItem item); | 39 | StreamPushItem transform(MediaItem item); |
| 39 | 40 | ||
| @@ -49,10 +50,10 @@ public interface IStreamPushService { | @@ -49,10 +50,10 @@ public interface IStreamPushService { | ||
| 49 | 50 | ||
| 50 | /** | 51 | /** |
| 51 | * 新的节点加入 | 52 | * 新的节点加入 |
| 52 | - * @param zlmServerConfig | 53 | + * @param mediaServerId |
| 53 | * @return | 54 | * @return |
| 54 | */ | 55 | */ |
| 55 | - void zlmServerOnline(ZLMServerConfig zlmServerConfig); | 56 | + void zlmServerOnline(String mediaServerId); |
| 56 | 57 | ||
| 57 | /** | 58 | /** |
| 58 | * 节点离线 | 59 | * 节点离线 |
| @@ -61,4 +62,5 @@ public interface IStreamPushService { | @@ -61,4 +62,5 @@ public interface IStreamPushService { | ||
| 61 | */ | 62 | */ |
| 62 | void zlmServerOffline(String mediaServerId); | 63 | void zlmServerOffline(String mediaServerId); |
| 63 | 64 | ||
| 65 | + void clean(); | ||
| 64 | } | 66 | } |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
| @@ -4,10 +4,10 @@ import com.alibaba.fastjson.JSON; | @@ -4,10 +4,10 @@ import com.alibaba.fastjson.JSON; | ||
| 4 | import com.alibaba.fastjson.JSONArray; | 4 | import com.alibaba.fastjson.JSONArray; |
| 5 | import com.alibaba.fastjson.JSONObject; | 5 | import com.alibaba.fastjson.JSONObject; |
| 6 | import com.genersoft.iot.vmp.common.VideoManagerConstants; | 6 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 7 | -import com.genersoft.iot.vmp.conf.MediaConfig; | ||
| 8 | import com.genersoft.iot.vmp.conf.SipConfig; | 7 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 9 | import com.genersoft.iot.vmp.conf.UserSetup; | 8 | import com.genersoft.iot.vmp.conf.UserSetup; |
| 10 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 9 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 10 | +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | ||
| 11 | import com.genersoft.iot.vmp.gb28181.session.SsrcConfig; | 11 | import com.genersoft.iot.vmp.gb28181.session.SsrcConfig; |
| 12 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | 12 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| 13 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | 13 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| @@ -71,6 +71,9 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR | @@ -71,6 +71,9 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR | ||
| 71 | private RedisUtil redisUtil; | 71 | private RedisUtil redisUtil; |
| 72 | 72 | ||
| 73 | @Autowired | 73 | @Autowired |
| 74 | + private EventPublisher publisher; | ||
| 75 | + | ||
| 76 | + @Autowired | ||
| 74 | JedisUtil jedisUtil; | 77 | JedisUtil jedisUtil; |
| 75 | 78 | ||
| 76 | private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | 79 | private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| @@ -312,8 +315,6 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR | @@ -312,8 +315,6 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR | ||
| 312 | return mediaServerMapper.update(mediaSerItem); | 315 | return mediaServerMapper.update(mediaSerItem); |
| 313 | } | 316 | } |
| 314 | 317 | ||
| 315 | - | ||
| 316 | - | ||
| 317 | /** | 318 | /** |
| 318 | * 处理zlm上线 | 319 | * 处理zlm上线 |
| 319 | * @param zlmServerConfig zlm上线携带的参数 | 320 | * @param zlmServerConfig zlm上线携带的参数 |
| @@ -353,28 +354,31 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR | @@ -353,28 +354,31 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR | ||
| 353 | if (serverItem.getRtpProxyPort() == 0) { | 354 | if (serverItem.getRtpProxyPort() == 0) { |
| 354 | serverItem.setRtpProxyPort(zlmServerConfig.getRtpProxyPort()); | 355 | serverItem.setRtpProxyPort(zlmServerConfig.getRtpProxyPort()); |
| 355 | } | 356 | } |
| 356 | - if (StringUtils.isEmpty(serverItem.getId())) { | ||
| 357 | - serverItem.setId(zlmServerConfig.getGeneralMediaServerId()); | ||
| 358 | - } | ||
| 359 | serverItem.setStatus(true); | 357 | serverItem.setStatus(true); |
| 358 | + | ||
| 360 | if (StringUtils.isEmpty(serverItem.getId())) { | 359 | if (StringUtils.isEmpty(serverItem.getId())) { |
| 361 | serverItem.setId(zlmServerConfig.getGeneralMediaServerId()); | 360 | serverItem.setId(zlmServerConfig.getGeneralMediaServerId()); |
| 362 | mediaServerMapper.updateByHostAndPort(serverItem); | 361 | mediaServerMapper.updateByHostAndPort(serverItem); |
| 363 | }else { | 362 | }else { |
| 364 | mediaServerMapper.update(serverItem); | 363 | mediaServerMapper.update(serverItem); |
| 365 | } | 364 | } |
| 366 | - String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetup.getServerId() + "_" + serverItem.getId(); | 365 | + String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetup.getServerId() + "_" + zlmServerConfig.getGeneralMediaServerId(); |
| 367 | if (redisUtil.get(key) == null) { | 366 | if (redisUtil.get(key) == null) { |
| 368 | - SsrcConfig ssrcConfig = new SsrcConfig(serverItem.getId(), null, sipConfig.getDomain()); | 367 | + SsrcConfig ssrcConfig = new SsrcConfig(zlmServerConfig.getGeneralMediaServerId(), null, sipConfig.getDomain()); |
| 369 | serverItem.setSsrcConfig(ssrcConfig); | 368 | serverItem.setSsrcConfig(ssrcConfig); |
| 370 | - redisUtil.set(key, serverItem); | 369 | + }else { |
| 370 | + MediaServerItem mediaServerItemInRedis = (MediaServerItem)redisUtil.get(key); | ||
| 371 | + serverItem.setSsrcConfig(mediaServerItemInRedis.getSsrcConfig()); | ||
| 371 | } | 372 | } |
| 372 | - | 373 | + redisUtil.set(key, serverItem); |
| 373 | resetOnlineServerItem(serverItem); | 374 | resetOnlineServerItem(serverItem); |
| 374 | updateMediaServerKeepalive(serverItem.getId(), null); | 375 | updateMediaServerKeepalive(serverItem.getId(), null); |
| 375 | setZLMConfig(serverItem); | 376 | setZLMConfig(serverItem); |
| 377 | + publisher.zlmOnlineEventPublish(serverItem.getId()); | ||
| 378 | + | ||
| 376 | } | 379 | } |
| 377 | 380 | ||
| 381 | + | ||
| 378 | @Override | 382 | @Override |
| 379 | public void zlmServerOffline(String mediaServerId) { | 383 | public void zlmServerOffline(String mediaServerId) { |
| 380 | delete(mediaServerId); | 384 | delete(mediaServerId); |
| @@ -567,6 +571,10 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR | @@ -567,6 +571,10 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR | ||
| 567 | @Override | 571 | @Override |
| 568 | public void updateMediaServerKeepalive(String mediaServerId, JSONObject data) { | 572 | public void updateMediaServerKeepalive(String mediaServerId, JSONObject data) { |
| 569 | MediaServerItem mediaServerItem = getOne(mediaServerId); | 573 | MediaServerItem mediaServerItem = getOne(mediaServerId); |
| 574 | + if (mediaServerItem == null) { | ||
| 575 | + logger.warn("[更新ZLM 保活信息]失败,未找到流媒体信息"); | ||
| 576 | + return; | ||
| 577 | + } | ||
| 570 | String key = VideoManagerConstants.MEDIA_SERVER_KEEPALIVE_PREFIX + userSetup.getServerId() + "_" + mediaServerId; | 578 | String key = VideoManagerConstants.MEDIA_SERVER_KEEPALIVE_PREFIX + userSetup.getServerId() + "_" + mediaServerId; |
| 571 | int hookAliveInterval = mediaServerItem.getHookAliveInterval() + 2; | 579 | int hookAliveInterval = mediaServerItem.getHookAliveInterval() + 2; |
| 572 | redisUtil.set(key, data, hookAliveInterval); | 580 | redisUtil.set(key, data, hookAliveInterval); |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
| @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.service.impl; | @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.service.impl; | ||
| 2 | 2 | ||
| 3 | import com.alibaba.fastjson.JSONObject; | 3 | import com.alibaba.fastjson.JSONObject; |
| 4 | import com.genersoft.iot.vmp.common.StreamInfo; | 4 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 5 | +import com.genersoft.iot.vmp.conf.UserSetup; | ||
| 5 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; | 6 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 6 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | 7 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 7 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | 8 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| @@ -28,8 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired; | @@ -28,8 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired; | ||
| 28 | import org.springframework.stereotype.Service; | 29 | import org.springframework.stereotype.Service; |
| 29 | import org.springframework.util.StringUtils; | 30 | import org.springframework.util.StringUtils; |
| 30 | 31 | ||
| 31 | -import java.util.ArrayList; | ||
| 32 | -import java.util.List; | 32 | +import java.util.*; |
| 33 | 33 | ||
| 34 | /** | 34 | /** |
| 35 | * 视频代理业务 | 35 | * 视频代理业务 |
| @@ -55,6 +55,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | @@ -55,6 +55,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | ||
| 55 | private IRedisCatchStorage redisCatchStorage; | 55 | private IRedisCatchStorage redisCatchStorage; |
| 56 | 56 | ||
| 57 | @Autowired | 57 | @Autowired |
| 58 | + private UserSetup userSetup; | ||
| 59 | + | ||
| 60 | + @Autowired | ||
| 58 | private GbStreamMapper gbStreamMapper; | 61 | private GbStreamMapper gbStreamMapper; |
| 59 | 62 | ||
| 60 | @Autowired | 63 | @Autowired |
| @@ -160,6 +163,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | @@ -160,6 +163,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | ||
| 160 | }else { | 163 | }else { |
| 161 | mediaServerItem = mediaServerService.getOne(param.getMediaServerId()); | 164 | mediaServerItem = mediaServerService.getOne(param.getMediaServerId()); |
| 162 | } | 165 | } |
| 166 | + if (mediaServerItem == null) { | ||
| 167 | + return null; | ||
| 168 | + } | ||
| 163 | if ("default".equals(param.getType())){ | 169 | if ("default".equals(param.getType())){ |
| 164 | result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl(), | 170 | result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl(), |
| 165 | param.isEnable_hls(), param.isEnable_mp4(), param.getRtp_type()); | 171 | param.isEnable_hls(), param.isEnable_mp4(), param.getRtp_type()); |
| @@ -244,7 +250,6 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | @@ -244,7 +250,6 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | ||
| 244 | } | 250 | } |
| 245 | } | 251 | } |
| 246 | } | 252 | } |
| 247 | - | ||
| 248 | return result; | 253 | return result; |
| 249 | } | 254 | } |
| 250 | 255 | ||
| @@ -255,18 +260,41 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | @@ -255,18 +260,41 @@ public class StreamProxyServiceImpl implements IStreamProxyService { | ||
| 255 | } | 260 | } |
| 256 | 261 | ||
| 257 | @Override | 262 | @Override |
| 258 | - public void zlmServerOnline(ZLMServerConfig zlmServerConfig) { | ||
| 259 | - | 263 | + public void zlmServerOnline(String mediaServerId) { |
| 264 | + zlmServerOffline(mediaServerId); | ||
| 260 | } | 265 | } |
| 261 | 266 | ||
| 262 | @Override | 267 | @Override |
| 263 | public void zlmServerOffline(String mediaServerId) { | 268 | public void zlmServerOffline(String mediaServerId) { |
| 264 | // 移除开启了无人观看自动移除的流 | 269 | // 移除开启了无人观看自动移除的流 |
| 270 | + List<StreamProxyItem> streamProxyItemList = streamProxyMapper.selecAutoRemoveItemByMediaServerId(mediaServerId); | ||
| 271 | + if (streamProxyItemList.size() > 0) { | ||
| 272 | + gbStreamMapper.batchDel(streamProxyItemList); | ||
| 273 | + } | ||
| 265 | streamProxyMapper.deleteAutoRemoveItemByMediaServerId(mediaServerId); | 274 | streamProxyMapper.deleteAutoRemoveItemByMediaServerId(mediaServerId); |
| 266 | // 其他的流设置未启用 | 275 | // 其他的流设置未启用 |
| 267 | streamProxyMapper.updateStatus(false, mediaServerId); | 276 | streamProxyMapper.updateStatus(false, mediaServerId); |
| 268 | - // 移除redis内流的信息 | ||
| 269 | - redisCatchStorage.removeStream(mediaServerId, "PULL"); | 277 | + String type = "PULL"; |
| 278 | + | ||
| 279 | + // 发送redis消息 | ||
| 280 | + List<StreamInfo> streamInfoList = redisCatchStorage.getStreams(mediaServerId, type); | ||
| 281 | + if (streamInfoList.size() > 0) { | ||
| 282 | + for (StreamInfo streamInfo : streamInfoList) { | ||
| 283 | + JSONObject jsonObject = new JSONObject(); | ||
| 284 | + jsonObject.put("serverId", userSetup.getServerId()); | ||
| 285 | + jsonObject.put("app", streamInfo.getApp()); | ||
| 286 | + jsonObject.put("stream", streamInfo.getStreamId()); | ||
| 287 | + jsonObject.put("register", false); | ||
| 288 | + jsonObject.put("mediaServerId", mediaServerId); | ||
| 289 | + redisCatchStorage.sendStreamChangeMsg(type, jsonObject); | ||
| 290 | + // 移除redis内流的信息 | ||
| 291 | + redisCatchStorage.removeStream(mediaServerId, type, streamInfo.getApp(), streamInfo.getStreamId()); | ||
| 292 | + } | ||
| 293 | + } | ||
| 294 | + } | ||
| 295 | + | ||
| 296 | + @Override | ||
| 297 | + public void clean() { | ||
| 270 | 298 | ||
| 271 | } | 299 | } |
| 272 | } | 300 | } |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
| @@ -3,11 +3,15 @@ package com.genersoft.iot.vmp.service.impl; | @@ -3,11 +3,15 @@ package com.genersoft.iot.vmp.service.impl; | ||
| 3 | import com.alibaba.fastjson.JSON; | 3 | import com.alibaba.fastjson.JSON; |
| 4 | import com.alibaba.fastjson.JSONObject; | 4 | import com.alibaba.fastjson.JSONObject; |
| 5 | import com.alibaba.fastjson.TypeReference; | 5 | import com.alibaba.fastjson.TypeReference; |
| 6 | +import com.genersoft.iot.vmp.common.StreamInfo; | ||
| 7 | +import com.genersoft.iot.vmp.conf.UserSetup; | ||
| 6 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; | 8 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 9 | +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; | ||
| 7 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | 10 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| 8 | import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; | 11 | import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; |
| 9 | import com.genersoft.iot.vmp.media.zlm.dto.MediaItem; | 12 | import com.genersoft.iot.vmp.media.zlm.dto.MediaItem; |
| 10 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | 13 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 14 | +import com.genersoft.iot.vmp.media.zlm.dto.OriginType; | ||
| 11 | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; | 15 | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| 12 | import com.genersoft.iot.vmp.service.IMediaServerService; | 16 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 13 | import com.genersoft.iot.vmp.service.IStreamPushService; | 17 | import com.genersoft.iot.vmp.service.IStreamPushService; |
| @@ -20,10 +24,7 @@ import com.github.pagehelper.PageInfo; | @@ -20,10 +24,7 @@ import com.github.pagehelper.PageInfo; | ||
| 20 | import org.springframework.beans.factory.annotation.Autowired; | 24 | import org.springframework.beans.factory.annotation.Autowired; |
| 21 | import org.springframework.stereotype.Service; | 25 | import org.springframework.stereotype.Service; |
| 22 | 26 | ||
| 23 | -import java.util.ArrayList; | ||
| 24 | -import java.util.HashMap; | ||
| 25 | -import java.util.List; | ||
| 26 | -import java.util.Map; | 27 | +import java.util.*; |
| 27 | 28 | ||
| 28 | @Service | 29 | @Service |
| 29 | public class StreamPushServiceImpl implements IStreamPushService { | 30 | public class StreamPushServiceImpl implements IStreamPushService { |
| @@ -44,6 +45,9 @@ public class StreamPushServiceImpl implements IStreamPushService { | @@ -44,6 +45,9 @@ public class StreamPushServiceImpl implements IStreamPushService { | ||
| 44 | private IRedisCatchStorage redisCatchStorage; | 45 | private IRedisCatchStorage redisCatchStorage; |
| 45 | 46 | ||
| 46 | @Autowired | 47 | @Autowired |
| 48 | + private UserSetup userSetup; | ||
| 49 | + | ||
| 50 | + @Autowired | ||
| 47 | private IMediaServerService mediaServerService; | 51 | private IMediaServerService mediaServerService; |
| 48 | 52 | ||
| 49 | @Override | 53 | @Override |
| @@ -56,7 +60,9 @@ public class StreamPushServiceImpl implements IStreamPushService { | @@ -56,7 +60,9 @@ public class StreamPushServiceImpl implements IStreamPushService { | ||
| 56 | for (MediaItem item : mediaItems) { | 60 | for (MediaItem item : mediaItems) { |
| 57 | 61 | ||
| 58 | // 不保存国标推理以及拉流代理的流 | 62 | // 不保存国标推理以及拉流代理的流 |
| 59 | - if (item.getOriginType() == 1 || item.getOriginType() == 2 || item.getOriginType() == 8) { | 63 | + if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal() |
| 64 | + || item.getOriginType() == OriginType.RTMP_PUSH.ordinal() | ||
| 65 | + || item.getOriginType() == OriginType.RTC_PUSH.ordinal() ) { | ||
| 60 | String key = item.getApp() + "_" + item.getStream(); | 66 | String key = item.getApp() + "_" + item.getStream(); |
| 61 | StreamPushItem streamPushItem = result.get(key); | 67 | StreamPushItem streamPushItem = result.get(key); |
| 62 | if (streamPushItem == null) { | 68 | if (streamPushItem == null) { |
| @@ -98,6 +104,11 @@ public class StreamPushServiceImpl implements IStreamPushService { | @@ -98,6 +104,11 @@ public class StreamPushServiceImpl implements IStreamPushService { | ||
| 98 | } | 104 | } |
| 99 | 105 | ||
| 100 | @Override | 106 | @Override |
| 107 | + public List<StreamPushItem> getPushList(String mediaServerId) { | ||
| 108 | + return streamPushMapper.selectAllByMediaServerId(mediaServerId); | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + @Override | ||
| 101 | public boolean saveToGB(GbStream stream) { | 112 | public boolean saveToGB(GbStream stream) { |
| 102 | stream.setStreamType("push"); | 113 | stream.setStreamType("push"); |
| 103 | stream.setStatus(true); | 114 | stream.setStatus(true); |
| @@ -137,17 +148,84 @@ public class StreamPushServiceImpl implements IStreamPushService { | @@ -137,17 +148,84 @@ public class StreamPushServiceImpl implements IStreamPushService { | ||
| 137 | } | 148 | } |
| 138 | 149 | ||
| 139 | @Override | 150 | @Override |
| 140 | - public void zlmServerOnline(ZLMServerConfig zlmServerConfig) { | ||
| 141 | - // 似乎没啥需要做的 | 151 | + public void zlmServerOnline(String mediaServerId) { |
| 152 | + // 同步zlm推流信息 | ||
| 153 | + MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); | ||
| 154 | + if (mediaServerItem == null) { | ||
| 155 | + return; | ||
| 156 | + } | ||
| 157 | + List<StreamPushItem> pushList = getPushList(mediaServerId); | ||
| 158 | + if (pushList.size() > 0) { | ||
| 159 | + Map<String, StreamPushItem> pushItemMap = new HashMap<>(); | ||
| 160 | + for (StreamPushItem streamPushItem : pushList) { | ||
| 161 | + pushItemMap.put(streamPushItem.getApp() + streamPushItem.getStream(), streamPushItem); | ||
| 162 | + } | ||
| 163 | + zlmresTfulUtils.getMediaList(mediaServerItem, (mediaList ->{ | ||
| 164 | + if (mediaList == null) return; | ||
| 165 | + String dataStr = mediaList.getString("data"); | ||
| 166 | + | ||
| 167 | + Integer code = mediaList.getInteger("code"); | ||
| 168 | + List<StreamPushItem> streamPushItems = null; | ||
| 169 | + if (code == 0 ) { | ||
| 170 | + if (dataStr != null) { | ||
| 171 | + streamPushItems = handleJSON(dataStr, mediaServerItem); | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + if (streamPushItems != null) { | ||
| 176 | + for (StreamPushItem streamPushItem : streamPushItems) { | ||
| 177 | + pushItemMap.remove(streamPushItem.getApp() + streamPushItem.getStream()); | ||
| 178 | + } | ||
| 179 | + } | ||
| 180 | + Collection<StreamPushItem> offlinePushItems = pushItemMap.values(); | ||
| 181 | + if (offlinePushItems.size() > 0) { | ||
| 182 | + String type = "PUSH"; | ||
| 183 | + streamPushMapper.delAll(new ArrayList<>(offlinePushItems)); | ||
| 184 | + for (StreamPushItem offlinePushItem : offlinePushItems) { | ||
| 185 | + JSONObject jsonObject = new JSONObject(); | ||
| 186 | + jsonObject.put("serverId", userSetup.getServerId()); | ||
| 187 | + jsonObject.put("app", offlinePushItem.getApp()); | ||
| 188 | + jsonObject.put("stream", offlinePushItem.getStream()); | ||
| 189 | + jsonObject.put("register", false); | ||
| 190 | + jsonObject.put("mediaServerId", mediaServerId); | ||
| 191 | + redisCatchStorage.sendStreamChangeMsg(type, jsonObject); | ||
| 192 | + // 移除redis内流的信息 | ||
| 193 | + redisCatchStorage.removeStream(mediaServerItem.getId(), "PUSH", offlinePushItem.getApp(), offlinePushItem.getStream()); | ||
| 194 | + } | ||
| 195 | + } | ||
| 196 | + })); | ||
| 197 | + } | ||
| 142 | } | 198 | } |
| 143 | 199 | ||
| 144 | @Override | 200 | @Override |
| 145 | public void zlmServerOffline(String mediaServerId) { | 201 | public void zlmServerOffline(String mediaServerId) { |
| 146 | - // 移除没有serverId的推流 | 202 | + List<StreamPushItem> streamPushItems = streamPushMapper.selectAllByMediaServerId(mediaServerId); |
| 203 | + // 移除没有GBId的推流 | ||
| 147 | streamPushMapper.deleteWithoutGBId(mediaServerId); | 204 | streamPushMapper.deleteWithoutGBId(mediaServerId); |
| 205 | + gbStreamMapper.deleteWithoutGBId("push", mediaServerId); | ||
| 148 | // 其他的流设置未启用 | 206 | // 其他的流设置未启用 |
| 149 | gbStreamMapper.updateStatusByMediaServerId(mediaServerId, false); | 207 | gbStreamMapper.updateStatusByMediaServerId(mediaServerId, false); |
| 150 | - // 移除redis内流的信息 | ||
| 151 | - redisCatchStorage.removeStream(mediaServerId, "PUSH"); | 208 | + // 发送流停止消息 |
| 209 | + String type = "PUSH"; | ||
| 210 | + // 发送redis消息 | ||
| 211 | + List<StreamInfo> streamInfoList = redisCatchStorage.getStreams(mediaServerId, type); | ||
| 212 | + if (streamInfoList.size() > 0) { | ||
| 213 | + for (StreamInfo streamInfo : streamInfoList) { | ||
| 214 | + JSONObject jsonObject = new JSONObject(); | ||
| 215 | + jsonObject.put("serverId", userSetup.getServerId()); | ||
| 216 | + jsonObject.put("app", streamInfo.getApp()); | ||
| 217 | + jsonObject.put("stream", streamInfo.getStreamId()); | ||
| 218 | + jsonObject.put("register", false); | ||
| 219 | + jsonObject.put("mediaServerId", mediaServerId); | ||
| 220 | + redisCatchStorage.sendStreamChangeMsg(type, jsonObject); | ||
| 221 | + // 移除redis内流的信息 | ||
| 222 | + redisCatchStorage.removeStream(mediaServerId, type, streamInfo.getApp(), streamInfo.getStreamId()); | ||
| 223 | + } | ||
| 224 | + } | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + @Override | ||
| 228 | + public void clean() { | ||
| 229 | + | ||
| 152 | } | 230 | } |
| 153 | } | 231 | } |
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
| @@ -140,11 +140,11 @@ public interface IRedisCatchStorage { | @@ -140,11 +140,11 @@ public interface IRedisCatchStorage { | ||
| 140 | 140 | ||
| 141 | /** | 141 | /** |
| 142 | * 移除流信息从redis | 142 | * 移除流信息从redis |
| 143 | - * @param mediaServerItem | 143 | + * @param mediaServerId |
| 144 | * @param app | 144 | * @param app |
| 145 | * @param streamId | 145 | * @param streamId |
| 146 | */ | 146 | */ |
| 147 | - void removeStream(MediaServerItem mediaServerItem, String type, String app, String streamId); | 147 | + void removeStream(String mediaServerId, String type, String app, String streamId); |
| 148 | 148 | ||
| 149 | 149 | ||
| 150 | /** | 150 | /** |
| @@ -167,4 +167,6 @@ public interface IRedisCatchStorage { | @@ -167,4 +167,6 @@ public interface IRedisCatchStorage { | ||
| 167 | * @return | 167 | * @return |
| 168 | */ | 168 | */ |
| 169 | ThirdPartyGB queryMemberNoGBId(String queryKey); | 169 | ThirdPartyGB queryMemberNoGBId(String queryKey); |
| 170 | + | ||
| 171 | + List<StreamInfo> getStreams(String mediaServerId, String pull); | ||
| 170 | } | 172 | } |
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
| @@ -65,4 +65,18 @@ public interface GbStreamMapper { | @@ -65,4 +65,18 @@ public interface GbStreamMapper { | ||
| 65 | "SET status=${status} " + | 65 | "SET status=${status} " + |
| 66 | "WHERE mediaServerId=#{mediaServerId} ") | 66 | "WHERE mediaServerId=#{mediaServerId} ") |
| 67 | void updateStatusByMediaServerId(String mediaServerId, boolean status); | 67 | void updateStatusByMediaServerId(String mediaServerId, boolean status); |
| 68 | + | ||
| 69 | + @Select("SELECT * FROM gb_stream WHERE mediaServerId=#{mediaServerId}") | ||
| 70 | + void delByMediaServerId(String mediaServerId); | ||
| 71 | + | ||
| 72 | + @Delete("DELETE FROM gb_stream WHERE streamType=#{type} AND gbId=NULL AND mediaServerId=#{mediaServerId}") | ||
| 73 | + void deleteWithoutGBId(String type, String mediaServerId); | ||
| 74 | + | ||
| 75 | + @Delete("<script> "+ | ||
| 76 | + "DELETE FROM gb_stream where " + | ||
| 77 | + "<foreach collection='streamProxyItemList' item='item' separator='or'>" + | ||
| 78 | + "(app=#{item.app} and stream=#{item.stream}) " + | ||
| 79 | + "</foreach>" + | ||
| 80 | + "</script>") | ||
| 81 | + void batchDel(List<StreamProxyItem> streamProxyItemList); | ||
| 68 | } | 82 | } |
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
| @@ -62,6 +62,9 @@ public interface StreamProxyMapper { | @@ -62,6 +62,9 @@ public interface StreamProxyMapper { | ||
| 62 | "WHERE mediaServerId=#{mediaServerId}") | 62 | "WHERE mediaServerId=#{mediaServerId}") |
| 63 | void updateStatus(boolean status, String mediaServerId); | 63 | void updateStatus(boolean status, String mediaServerId); |
| 64 | 64 | ||
| 65 | - @Delete("DELETE FROM stream_proxy WHERE mediaServerId=#{mediaServerId}") | 65 | + @Delete("DELETE FROM stream_proxy WHERE enable_remove_none_reader=true AND mediaServerId=#{mediaServerId}") |
| 66 | void deleteAutoRemoveItemByMediaServerId(String mediaServerId); | 66 | void deleteAutoRemoveItemByMediaServerId(String mediaServerId); |
| 67 | + | ||
| 68 | + @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable_remove_none_reader=true AND st.mediaServerId=#{mediaServerId} order by st.createTime desc") | ||
| 69 | + List<StreamProxyItem> selecAutoRemoveItemByMediaServerId(String mediaServerId); | ||
| 67 | } | 70 | } |
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
| @@ -4,6 +4,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; | @@ -4,6 +4,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; | ||
| 4 | import org.apache.ibatis.annotations.*; | 4 | import org.apache.ibatis.annotations.*; |
| 5 | import org.springframework.stereotype.Repository; | 5 | import org.springframework.stereotype.Repository; |
| 6 | 6 | ||
| 7 | +import java.util.Collection; | ||
| 7 | import java.util.List; | 8 | import java.util.List; |
| 8 | 9 | ||
| 9 | @Mapper | 10 | @Mapper |
| @@ -31,6 +32,14 @@ public interface StreamPushMapper { | @@ -31,6 +32,14 @@ public interface StreamPushMapper { | ||
| 31 | @Delete("DELETE FROM stream_push WHERE app=#{app} AND stream=#{stream}") | 32 | @Delete("DELETE FROM stream_push WHERE app=#{app} AND stream=#{stream}") |
| 32 | int del(String app, String stream); | 33 | int del(String app, String stream); |
| 33 | 34 | ||
| 35 | + @Delete("<script> "+ | ||
| 36 | + "DELETE FROM stream_push where " + | ||
| 37 | + "<foreach collection='streamPushItems' item='item' separator='or'>" + | ||
| 38 | + "(app=#{item.app} and stream=#{item.stream}) " + | ||
| 39 | + "</foreach>" + | ||
| 40 | + "</script>") | ||
| 41 | + int delAll(List<StreamPushItem> streamPushItems); | ||
| 42 | + | ||
| 34 | @Select("SELECT st.*, pgs.gbId, pgs.status, pgs.name, pgs.longitude, pgs.latitude FROM stream_push st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream") | 43 | @Select("SELECT st.*, pgs.gbId, pgs.status, pgs.name, pgs.longitude, pgs.latitude FROM stream_push st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream") |
| 35 | List<StreamPushItem> selectAll(); | 44 | List<StreamPushItem> selectAll(); |
| 36 | 45 | ||
| @@ -56,4 +65,7 @@ public interface StreamPushMapper { | @@ -56,4 +65,7 @@ public interface StreamPushMapper { | ||
| 56 | @Delete("DELETE FROM stream_push WHERE mediaServerId=#{mediaServerId}") | 65 | @Delete("DELETE FROM stream_push WHERE mediaServerId=#{mediaServerId}") |
| 57 | void deleteWithoutGBId(String mediaServerId); | 66 | void deleteWithoutGBId(String mediaServerId); |
| 58 | 67 | ||
| 68 | + @Select("SELECT * FROM stream_push WHERE mediaServerId=#{mediaServerId}") | ||
| 69 | + List<StreamPushItem> selectAllByMediaServerId(String mediaServerId); | ||
| 70 | + | ||
| 59 | } | 71 | } |
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
| @@ -338,8 +338,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { | @@ -338,8 +338,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { | ||
| 338 | } | 338 | } |
| 339 | 339 | ||
| 340 | @Override | 340 | @Override |
| 341 | - public void removeStream(MediaServerItem mediaServerItem, String type, String app, String streamId) { | ||
| 342 | - String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetup.getServerId() + "_" + type + "_" + app + "_" + streamId + "_" + mediaServerItem.getId(); | 341 | + public void removeStream(String mediaServerId, String type, String app, String streamId) { |
| 342 | + String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetup.getServerId() + "_" + type + "_" + app + "_" + streamId + "_" + mediaServerId; | ||
| 343 | redis.del(key); | 343 | redis.del(key); |
| 344 | } | 344 | } |
| 345 | 345 | ||
| @@ -365,4 +365,16 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { | @@ -365,4 +365,16 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { | ||
| 365 | redis.del((String) stream); | 365 | redis.del((String) stream); |
| 366 | } | 366 | } |
| 367 | } | 367 | } |
| 368 | + | ||
| 369 | + @Override | ||
| 370 | + public List<StreamInfo> getStreams(String mediaServerId, String type) { | ||
| 371 | + List<StreamInfo> result = new ArrayList<>(); | ||
| 372 | + String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetup.getServerId() + "_" + type + "_*_*_" + mediaServerId; | ||
| 373 | + List<Object> streams = redis.scan(key); | ||
| 374 | + for (Object stream : streams) { | ||
| 375 | + StreamInfo streamInfo = (StreamInfo)redis.get((String) stream); | ||
| 376 | + result.add(streamInfo); | ||
| 377 | + } | ||
| 378 | + return result; | ||
| 379 | + } | ||
| 368 | } | 380 | } |