Commit fd091e545ba174adc36a9d3370e6d4c040ad33fd

Authored by 648540858
1 parent f84eebdb

优化hook订阅机制

src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
... ... @@ -10,6 +10,9 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
10 10 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
11 11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
12 12 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
  13 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  14 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
  15 +import com.genersoft.iot.vmp.media.zlm.dto.HookType;
13 16 import com.genersoft.iot.vmp.utils.DateUtil;
14 17 import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
15 18 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
... ... @@ -348,25 +351,19 @@ public class SIPCommander implements ISIPCommander {
348 351 @Override
349 352 public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
350 353 ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
351   - String streamId = ssrcInfo.getStream();
  354 + String stream = ssrcInfo.getStream();
352 355 try {
353 356 if (device == null) {
354 357 return;
355 358 }
356 359 String streamMode = device.getStreamMode().toUpperCase();
357 360  
358   - logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
359   - // 添加订阅
360   - JSONObject subscribeKey = new JSONObject();
361   - subscribeKey.put("app", "rtp");
362   - subscribeKey.put("stream", streamId);
363   - subscribeKey.put("regist", true);
364   - subscribeKey.put("schema", "rtmp");
365   - subscribeKey.put("mediaServerId", mediaServerItem.getId());
366   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
367   - (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  361 + logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
  362 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtmp", mediaServerItem.getId());
  363 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
368 364 if (event != null) {
369 365 event.response(mediaServerItemInUse, json);
  366 + subscribe.removeSubscribe(hookSubscribe);
370 367 }
371 368 });
372 369 //
... ... @@ -440,7 +437,7 @@ public class SIPCommander implements ISIPCommander {
440 437 errorEvent.response(e);
441 438 }), e ->{
442 439 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
443   - streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play);
  440 + streamSession.put(device.getDeviceId(), channelId ,"play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play);
444 441 streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog);
445 442 okEvent.response(e);
446 443 });
... ... @@ -530,21 +527,14 @@ public class SIPCommander implements ISIPCommander {
530 527  
531 528 CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
532 529 : udpSipProvider.getNewCallId();
533   -
  530 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtmp", mediaServerItem.getId());
534 531 // 添加订阅
535   - JSONObject subscribeKey = new JSONObject();
536   - subscribeKey.put("app", "rtp");
537   - subscribeKey.put("stream", ssrcInfo.getStream());
538   - subscribeKey.put("regist", true);
539   - subscribeKey.put("schema", "rtmp");
540   - subscribeKey.put("mediaServerId", mediaServerItem.getId());
541   - logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey);
542   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
543   - (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  532 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
544 533 if (hookEvent != null) {
545 534 InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream());
546 535 hookEvent.call(inviteStreamInfo);
547 536 }
  537 + subscribe.removeSubscribe(hookSubscribe);
548 538 });
549 539 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
550 540  
... ... @@ -643,21 +633,15 @@ public class SIPCommander implements ISIPCommander {
643 633 CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
644 634 : udpSipProvider.getNewCallId();
645 635  
  636 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId());
646 637 // 添加订阅
647   - JSONObject subscribeKey = new JSONObject();
648   - subscribeKey.put("app", "rtp");
649   - subscribeKey.put("stream", ssrcInfo.getStream());
650   - subscribeKey.put("regist", true);
651   - subscribeKey.put("mediaServerId", mediaServerItem.getId());
652   - logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
653   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
654   - (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  638 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
655 639 hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
656   - subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
657   - subscribeKey.put("regist", false);
658   - subscribeKey.put("schema", "rtmp");
  640 + subscribe.removeSubscribe(hookSubscribe);
  641 + hookSubscribe.getContent().put("regist", false);
  642 + hookSubscribe.getContent().put("schema", "rtmp");
659 643 // 添加流注销的订阅,注销了后向设备发送bye
660   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  644 + subscribe.addSubscribe(hookSubscribe,
661 645 (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd)->{
662 646 ClientTransaction transaction = streamSession.getTransaction(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId());
663 647 if (transaction != null) {
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -102,7 +102,7 @@ public class ZLMHttpHookListener {
102 102 logger.debug("[ ZLM HOOK ] on_server_keepalive API调用,参数:" + json.toString());
103 103 }
104 104 String mediaServerId = json.getString("mediaServerId");
105   - List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_keepalive);
  105 + List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
106 106 if (subscribes != null && subscribes.size() > 0) {
107 107 for (ZLMHttpHookSubscribe.Event subscribe : subscribes) {
108 108 subscribe.response(null, json);
... ... @@ -168,7 +168,7 @@ public class ZLMHttpHookListener {
168 168 logger.debug("[ ZLM HOOK ]on_play API调用,参数:" + JSON.toJSONString(param));
169 169 }
170 170 String mediaServerId = param.getMediaServerId();
171   - ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_play, json);
  171 + ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json);
172 172 if (subscribe != null ) {
173 173 MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
174 174 if (mediaInfo != null) {
... ... @@ -253,7 +253,7 @@ public class ZLMHttpHookListener {
253 253 }
254 254  
255 255  
256   - ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
  256 + ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);
257 257 if (subscribe != null) {
258 258 if (mediaInfo != null) {
259 259 subscribe.response(mediaInfo, json);
... ... @@ -377,7 +377,7 @@ public class ZLMHttpHookListener {
377 377 logger.debug("[ ZLM HOOK ]on_shell_login API调用,参数:" + json.toString());
378 378 }
379 379 String mediaServerId = json.getString("mediaServerId");
380   - ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_shell_login, json);
  380 + ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_shell_login, json);
381 381 if (subscribe != null ) {
382 382 MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
383 383 if (mediaInfo != null) {
... ... @@ -403,7 +403,7 @@ public class ZLMHttpHookListener {
403 403 logger.info("[ ZLM HOOK ]on_stream_changed API调用,参数:" + JSONObject.toJSONString(item));
404 404 String mediaServerId = item.getMediaServerId();
405 405 JSONObject json = (JSONObject) JSON.toJSON(item);
406   - ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, json);
  406 + ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);
407 407 if (subscribe != null ) {
408 408 MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
409 409 if (mediaInfo != null) {
... ... @@ -614,7 +614,7 @@ public class ZLMHttpHookListener {
614 614 }
615 615 String remoteAddr = request.getRemoteAddr();
616 616 jsonObject.put("ip", remoteAddr);
617   - List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_started);
  617 + List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);
618 618 if (subscribes != null && subscribes.size() > 0) {
619 619 for (ZLMHttpHookSubscribe.Event subscribe : subscribes) {
620 620 subscribe.response(null, jsonObject);
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
1 1 package com.genersoft.iot.vmp.media.zlm;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.media.zlm.dto.HookType;
  5 +import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
4 6 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
5 7 import org.springframework.stereotype.Component;
6 8 import org.springframework.util.CollectionUtils;
7 9  
  10 +import java.time.Instant;
8 11 import java.util.*;
9 12 import java.util.concurrent.ConcurrentHashMap;
  13 +import java.util.concurrent.TimeUnit;
10 14  
11 15 /**
12 16 * @description:针对 ZLMediaServer的hook事件订阅
... ... @@ -16,49 +20,38 @@ import java.util.concurrent.ConcurrentHashMap;
16 20 @Component
17 21 public class ZLMHttpHookSubscribe {
18 22  
19   - public enum HookType{
20   - on_flow_report,
21   - on_http_access,
22   - on_play,
23   - on_publish,
24   - on_record_mp4,
25   - on_rtsp_auth,
26   - on_rtsp_realm,
27   - on_shell_login,
28   - on_stream_changed,
29   - on_stream_none_reader,
30   - on_stream_not_found,
31   - on_server_started,
32   - on_server_keepalive
33   - }
34   -
35 23 @FunctionalInterface
36 24 public interface Event{
37 25 void response(MediaServerItem mediaServerItem, JSONObject response);
38 26 }
39 27  
40   - private Map<HookType, Map<JSONObject, ZLMHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
  28 + private Map<HookType, Map<IHookSubscribe, ZLMHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
41 29  
42   - public void addSubscribe(HookType type, JSONObject hookResponse, ZLMHttpHookSubscribe.Event event) {
43   - allSubscribes.computeIfAbsent(type, k -> new ConcurrentHashMap<>()).put(hookResponse, event);
  30 + public void addSubscribe(IHookSubscribe hookSubscribe, ZLMHttpHookSubscribe.Event event) {
  31 + if (hookSubscribe.getExpires() == null) {
  32 + // 默认5分钟过期
  33 + Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.MINUTES.toSeconds(5));
  34 + hookSubscribe.setExpires(expiresInstant);
  35 + }
  36 + allSubscribes.computeIfAbsent(hookSubscribe.getHookType(), k -> new ConcurrentHashMap<>()).put(hookSubscribe, event);
44 37 }
45 38  
46   - public ZLMHttpHookSubscribe.Event getSubscribe(HookType type, JSONObject hookResponse) {
  39 + public ZLMHttpHookSubscribe.Event sendNotify(HookType type, JSONObject hookResponse) {
47 40 ZLMHttpHookSubscribe.Event event= null;
48   - Map<JSONObject, Event> eventMap = allSubscribes.get(type);
  41 + Map<IHookSubscribe, Event> eventMap = allSubscribes.get(type);
49 42 if (eventMap == null) {
50 43 return null;
51 44 }
52   - for (JSONObject key : eventMap.keySet()) {
  45 + for (IHookSubscribe key : eventMap.keySet()) {
53 46 Boolean result = null;
54   - for (String s : key.keySet()) {
  47 + for (String s : key.getContent().keySet()) {
55 48 if (result == null) {
56   - result = key.getString(s).equals(hookResponse.getString(s));
  49 + result = key.getContent().getString(s).equals(hookResponse.getString(s));
57 50 }else {
58   - if (key.getString(s) == null) {
  51 + if (key.getContent().getString(s) == null) {
59 52 continue;
60 53 }
61   - result = result && key.getString(s).equals(hookResponse.getString(s));
  54 + result = result && key.getContent().getString(s).equals(hookResponse.getString(s));
62 55 }
63 56  
64 57 }
... ... @@ -69,26 +62,30 @@ public class ZLMHttpHookSubscribe {
69 62 return event;
70 63 }
71 64  
72   - public void removeSubscribe(HookType type, JSONObject hookResponse) {
73   - Map<JSONObject, Event> eventMap = allSubscribes.get(type);
  65 + public void removeSubscribe(IHookSubscribe hookSubscribe) {
  66 + Map<IHookSubscribe, Event> eventMap = allSubscribes.get(hookSubscribe.getHookType());
74 67 if (eventMap == null) {
75 68 return;
76 69 }
77 70  
78   - Set<Map.Entry<JSONObject, Event>> entries = eventMap.entrySet();
  71 + Set<Map.Entry<IHookSubscribe, Event>> entries = eventMap.entrySet();
79 72 if (entries.size() > 0) {
80   - List<Map.Entry<JSONObject, ZLMHttpHookSubscribe.Event>> entriesToRemove = new ArrayList<>();
81   - for (Map.Entry<JSONObject, ZLMHttpHookSubscribe.Event> entry : entries) {
82   - JSONObject key = entry.getKey();
  73 + List<Map.Entry<IHookSubscribe, ZLMHttpHookSubscribe.Event>> entriesToRemove = new ArrayList<>();
  74 + for (Map.Entry<IHookSubscribe, ZLMHttpHookSubscribe.Event> entry : entries) {
  75 + JSONObject content = entry.getKey().getContent();
  76 + if (content == null || content.size() == 0) {
  77 + entriesToRemove.add(entry);
  78 + continue;
  79 + }
83 80 Boolean result = null;
84   - for (String s : key.keySet()) {
  81 + for (String s : content.keySet()) {
85 82 if (result == null) {
86   - result = key.getString(s).equals(hookResponse.getString(s));
  83 + result = content.getString(s).equals(hookSubscribe.getContent().getString(s));
87 84 }else {
88   - if (key.getString(s) == null) {
  85 + if (content.getString(s) == null) {
89 86 continue;
90 87 }
91   - result = result && key.getString(s).equals(hookResponse.getString(s));
  88 + result = result && content.getString(s).equals(hookSubscribe.getContent().getString(s));
92 89 }
93 90 }
94 91 if (null != result && result){
... ... @@ -97,7 +94,7 @@ public class ZLMHttpHookSubscribe {
97 94 }
98 95  
99 96 if (!CollectionUtils.isEmpty(entriesToRemove)) {
100   - for (Map.Entry<JSONObject, ZLMHttpHookSubscribe.Event> entry : entriesToRemove) {
  97 + for (Map.Entry<IHookSubscribe, ZLMHttpHookSubscribe.Event> entry : entriesToRemove) {
101 98 entries.remove(entry);
102 99 }
103 100 }
... ... @@ -111,17 +108,25 @@ public class ZLMHttpHookSubscribe {
111 108 * @return
112 109 */
113 110 public List<ZLMHttpHookSubscribe.Event> getSubscribes(HookType type) {
114   - // ZLMHttpHookSubscribe.Event event= null;
115   - Map<JSONObject, Event> eventMap = allSubscribes.get(type);
  111 + Map<IHookSubscribe, Event> eventMap = allSubscribes.get(type);
116 112 if (eventMap == null) {
117 113 return null;
118 114 }
119 115 List<ZLMHttpHookSubscribe.Event> result = new ArrayList<>();
120   - for (JSONObject key : eventMap.keySet()) {
  116 + for (IHookSubscribe key : eventMap.keySet()) {
121 117 result.add(eventMap.get(key));
122 118 }
123 119 return result;
124 120 }
125 121  
  122 + public List<IHookSubscribe> getAll(){
  123 + ArrayList<IHookSubscribe> result = new ArrayList<>();
  124 + Collection<Map<IHookSubscribe, Event>> values = allSubscribes.values();
  125 + for (Map<IHookSubscribe, Event> value : values) {
  126 + result.addAll(value.keySet());
  127 + }
  128 + return result;
  129 + }
  130 +
126 131  
127 132 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
... ... @@ -6,22 +6,22 @@ import com.alibaba.fastjson.JSONObject;
6 6 import com.genersoft.iot.vmp.conf.DynamicTask;
7 7 import com.genersoft.iot.vmp.conf.MediaConfig;
8 8 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
  9 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  10 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForServerStarted;
  11 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
9 12 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
10 13 import com.genersoft.iot.vmp.service.IMediaServerService;
11   -import com.genersoft.iot.vmp.service.IStreamProxyService;
12   -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
13 14 import org.slf4j.Logger;
14 15 import org.slf4j.LoggerFactory;
15 16 import org.springframework.beans.factory.annotation.Autowired;
16   -import org.springframework.beans.factory.annotation.Qualifier;
17 17 import org.springframework.boot.CommandLineRunner;
18 18 import org.springframework.core.annotation.Order;
19 19 import org.springframework.scheduling.annotation.Async;
20   -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
21 20 import org.springframework.stereotype.Component;
22   -import org.springframework.util.StringUtils;
23 21  
  22 +import java.time.Instant;
24 23 import java.util.*;
  24 +import java.util.concurrent.TimeUnit;
25 25  
26 26 @Component
27 27 @Order(value=1)
... ... @@ -38,18 +38,12 @@ public class ZLMRunner implements CommandLineRunner {
38 38 private ZLMHttpHookSubscribe hookSubscribe;
39 39  
40 40 @Autowired
41   - private IStreamProxyService streamProxyService;
42   -
43   - @Autowired
44 41 private EventPublisher publisher;
45 42  
46 43 @Autowired
47 44 private IMediaServerService mediaServerService;
48 45  
49 46 @Autowired
50   - private IRedisCatchStorage redisCatchStorage;
51   -
52   - @Autowired
53 47 private MediaConfig mediaConfig;
54 48  
55 49 @Autowired
... ... @@ -67,17 +61,25 @@ public class ZLMRunner implements CommandLineRunner {
67 61 mediaServerService.updateToDatabase(mediaSerItem);
68 62 }
69 63 mediaServerService.syncCatchFromDatabase();
  64 + HookSubscribeForServerStarted hookSubscribeForServerStarted = HookSubscribeFactory.on_server_started();
  65 +// Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.SECONDS.toSeconds(60));
  66 +// hookSubscribeForStreamChange.setExpires(expiresInstant);
70 67 // 订阅 zlm启动事件, 新的zlm也会从这里进入系统
71   - hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,new JSONObject(),
  68 + hookSubscribe.addSubscribe(hookSubscribeForServerStarted,
72 69 (MediaServerItem mediaServerItem, JSONObject response)->{
73 70 ZLMServerConfig zlmServerConfig = JSONObject.toJavaObject(response, ZLMServerConfig.class);
74 71 if (zlmServerConfig !=null ) {
75 72 if (startGetMedia != null) {
76 73 startGetMedia.remove(zlmServerConfig.getGeneralMediaServerId());
  74 + if (startGetMedia.size() == 0) {
  75 + hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started());
  76 + }
77 77 }
78 78 }
79 79 });
80 80  
  81 +
  82 +
81 83 // 获取zlm信息
82 84 logger.info("[zlm] 等待默认zlm中...");
83 85  
... ... @@ -103,7 +105,6 @@ public class ZLMRunner implements CommandLineRunner {
103 105 }
104 106 startGetMedia = null;
105 107 }
106   - hookSubscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started, new JSONObject());
107 108 // TODO 清理数据库中与redis不匹配的zlm
108 109 }, 60 * 1000 );
109 110 }
... ... @@ -116,6 +117,9 @@ public class ZLMRunner implements CommandLineRunner {
116 117 zlmServerConfigFirst.setIp(mediaServerItem.getIp());
117 118 zlmServerConfigFirst.setHttpPort(mediaServerItem.getHttpPort());
118 119 startGetMedia.remove(mediaServerItem.getId());
  120 + if (startGetMedia.size() == 0) {
  121 + hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started());
  122 + }
119 123 mediaServerService.zlmServerOnline(zlmServerConfigFirst);
120 124 }else {
121 125 logger.info("[ {} ]-[ {}:{} ]主动连接失败, 清理相关资源, 开始尝试重试连接",
... ... @@ -130,6 +134,9 @@ public class ZLMRunner implements CommandLineRunner {
130 134 zlmServerConfig.setIp(mediaServerItem.getIp());
131 135 zlmServerConfig.setHttpPort(mediaServerItem.getHttpPort());
132 136 startGetMedia.remove(mediaServerItem.getId());
  137 + if (startGetMedia.size() == 0) {
  138 + hookSubscribe.removeSubscribe(HookSubscribeFactory.on_server_started());
  139 + }
133 140 mediaServerService.zlmServerOnline(zlmServerConfig);
134 141 }
135 142 }, 2000);
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm.dto;
  2 +
  3 +
  4 +import com.alibaba.fastjson.JSONObject;
  5 +
  6 +/**
  7 + * hook 订阅工厂
  8 + * @author lin
  9 + */
  10 +public class HookSubscribeFactory {
  11 +
  12 + public static HookSubscribeForStreamChange on_stream_changed(String app, String stream, boolean regist, String scheam, String mediaServerId) {
  13 + HookSubscribeForStreamChange hookSubscribe = new HookSubscribeForStreamChange();
  14 + JSONObject subscribeKey = new com.alibaba.fastjson.JSONObject();
  15 + subscribeKey.put("app", app);
  16 + subscribeKey.put("stream", stream);
  17 + subscribeKey.put("regist", regist);
  18 + if (scheam != null) {
  19 + subscribeKey.put("schema", scheam);
  20 + }
  21 + subscribeKey.put("mediaServerId", mediaServerId);
  22 + hookSubscribe.setContent(subscribeKey);
  23 +
  24 + return hookSubscribe;
  25 + }
  26 +
  27 + public static HookSubscribeForServerStarted on_server_started() {
  28 + HookSubscribeForServerStarted hookSubscribe = new HookSubscribeForServerStarted();
  29 + hookSubscribe.setContent(new JSONObject());
  30 +
  31 + return hookSubscribe;
  32 + }
  33 +}
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForServerStarted.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm.dto;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.alibaba.fastjson.annotation.JSONField;
  5 +
  6 +import java.time.Instant;
  7 +
  8 +/**
  9 + * hook订阅-流变化
  10 + * @author lin
  11 + */
  12 +public class HookSubscribeForServerStarted implements IHookSubscribe{
  13 +
  14 + private HookType hookType = HookType.on_server_started;
  15 +
  16 + private JSONObject content;
  17 +
  18 + @JSONField(format="yyyy-MM-dd HH:mm:ss")
  19 + private Instant expires;
  20 +
  21 + @Override
  22 + public HookType getHookType() {
  23 + return hookType;
  24 + }
  25 +
  26 + @Override
  27 + public JSONObject getContent() {
  28 + return content;
  29 + }
  30 +
  31 + public void setContent(JSONObject content) {
  32 + this.content = content;
  33 + }
  34 +
  35 + @Override
  36 + public Instant getExpires() {
  37 + return expires;
  38 + }
  39 +
  40 + @Override
  41 + public void setExpires(Instant expires) {
  42 + this.expires = expires;
  43 + }
  44 +}
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamChange.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm.dto;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.alibaba.fastjson.annotation.JSONField;
  5 +
  6 +import java.time.Instant;
  7 +
  8 +/**
  9 + * hook订阅-流变化
  10 + * @author lin
  11 + */
  12 +public class HookSubscribeForStreamChange implements IHookSubscribe{
  13 +
  14 + private HookType hookType = HookType.on_stream_changed;
  15 +
  16 + private JSONObject content;
  17 +
  18 + private Instant expires;
  19 +
  20 + @Override
  21 + public HookType getHookType() {
  22 + return hookType;
  23 + }
  24 +
  25 + @Override
  26 + public JSONObject getContent() {
  27 + return content;
  28 + }
  29 +
  30 + public void setContent(JSONObject content) {
  31 + this.content = content;
  32 + }
  33 +
  34 + @Override
  35 + public Instant getExpires() {
  36 + return expires;
  37 + }
  38 +
  39 + @Override
  40 + public void setExpires(Instant expires) {
  41 + this.expires = expires;
  42 + }
  43 +}
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookType.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm.dto;
  2 +
  3 +/**
  4 + * hook类型
  5 + * @author lin
  6 + */
  7 +
  8 +public enum HookType {
  9 +
  10 + on_flow_report,
  11 + on_http_access,
  12 + on_play,
  13 + on_publish,
  14 + on_record_mp4,
  15 + on_rtsp_auth,
  16 + on_rtsp_realm,
  17 + on_shell_login,
  18 + on_stream_changed,
  19 + on_stream_none_reader,
  20 + on_stream_not_found,
  21 + on_server_started,
  22 + on_server_keepalive
  23 +}
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IHookSubscribe.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm.dto;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +
  5 +import java.time.Instant;
  6 +
  7 +/**
  8 + * zlm hook事件的参数
  9 + * @author lin
  10 + */
  11 +public interface IHookSubscribe {
  12 +
  13 + /**
  14 + * 获取hook类型
  15 + * @return hook类型
  16 + */
  17 + HookType getHookType();
  18 +
  19 + /**
  20 + * 获取hook的具体内容
  21 + * @return hook的具体内容
  22 + */
  23 + JSONObject getContent();
  24 +
  25 + /**
  26 + * 设置过期时间
  27 + * @param instant 过期时间
  28 + */
  29 + void setExpires(Instant instant);
  30 +
  31 + /**
  32 + * 获取过期时间
  33 + * @return 过期时间
  34 + */
  35 + Instant getExpires();
  36 +}
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
... ... @@ -13,6 +13,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
13 13 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
14 14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
15 15 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
  16 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  17 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
  18 +import com.genersoft.iot.vmp.media.zlm.dto.HookType;
16 19 import com.genersoft.iot.vmp.utils.DateUtil;
17 20 import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
18 21 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
... ... @@ -296,16 +299,10 @@ public class PlayServiceImpl implements IPlayService {
296 299 // 单端口模式streamId也有变化,需要重新设置监听
297 300 if (!mediaServerItem.isRtpEnable()) {
298 301 // 添加订阅
299   - JSONObject subscribeKey = new JSONObject();
300   - subscribeKey.put("app", "rtp");
301   - subscribeKey.put("stream", stream);
302   - subscribeKey.put("regist", true);
303   - subscribeKey.put("schema", "rtmp");
304   - subscribeKey.put("mediaServerId", mediaServerItem.getId());
305   - subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed,subscribeKey);
306   - subscribeKey.put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
307   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
308   - (MediaServerItem mediaServerItemInUse, JSONObject response)->{
  302 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtmp", mediaServerItem.getId());
  303 + subscribe.removeSubscribe(hookSubscribe);
  304 + hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
  305 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{
309 306 logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
310 307 dynamicTask.stop(timeOutTaskKey);
311 308 // hook响应
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/RedisGbPlayMsgListener.java
... ... @@ -8,6 +8,9 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
8 8 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
9 9 import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
10 10 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
  11 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  12 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
  13 +import com.genersoft.iot.vmp.media.zlm.dto.HookType;
11 14 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 15 import com.genersoft.iot.vmp.service.IMediaServerService;
13 16 import com.genersoft.iot.vmp.service.bean.*;
... ... @@ -270,14 +273,9 @@ public class RedisGbPlayMsgListener implements MessageListener {
270 273 }, userSetting.getPlatformPlayTimeout());
271 274  
272 275 // 添加订阅
273   - JSONObject subscribeKey = new JSONObject();
274   - subscribeKey.put("app", content.getApp());
275   - subscribeKey.put("stream", content.getStream());
276   - subscribeKey.put("regist", true);
277   - subscribeKey.put("schema", "rtmp");
278   - subscribeKey.put("mediaServerId", mediaServerItem.getId());
279   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
280   - (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  276 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(content.getApp(), content.getStream(), true, "rtmp", mediaServerItem.getId());
  277 +
  278 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
281 279 dynamicTask.stop(taskKey);
282 280 responseSendItem(mediaServerItem, content, toId, serial);
283 281 });
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
... ... @@ -8,6 +8,8 @@ import com.genersoft.iot.vmp.conf.DynamicTask;
8 8 import com.genersoft.iot.vmp.conf.SipConfig;
9 9 import com.genersoft.iot.vmp.conf.UserSetting;
10 10 import com.genersoft.iot.vmp.conf.VersionInfo;
  11 +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
  12 +import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
11 13 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 14 import com.genersoft.iot.vmp.service.IMediaServerService;
13 15 import com.genersoft.iot.vmp.utils.SpringBeanFactory;
... ... @@ -38,7 +40,7 @@ import java.util.Set;
38 40 public class ServerController {
39 41  
40 42 @Autowired
41   - private ConfigurableApplicationContext context;
  43 + private ZLMHttpHookSubscribe zlmHttpHookSubscribe;
42 44  
43 45 @Autowired
44 46 private IMediaServerService mediaServerService;
... ... @@ -254,6 +256,18 @@ public class ServerController {
254 256 return result;
255 257 }
256 258  
  259 + @ApiOperation("获取当前所有hook")
  260 + @GetMapping(value = "/hooks")
  261 + @ResponseBody
  262 + public WVPResult<List<IHookSubscribe>> getHooks(){
  263 + WVPResult<List<IHookSubscribe>> result = new WVPResult<>();
  264 + result.setCode(0);
  265 + result.setMsg("success");
  266 + List<IHookSubscribe> all = zlmHttpHookSubscribe.getAll();
  267 + result.setData(all);
  268 + return result;
  269 + }
  270 +
257 271 // @ApiOperation("当前进行中的动态任务")
258 272 // @GetMapping(value = "/dynamicTask")
259 273 // @ResponseBody
... ...