Commit 42901d03746d534d701ea3b8663e1c6d2c938c6d

Authored by mrjackwang
Committed by GitHub
2 parents 1cb2b2cc 28e5c1ae

Merge branch 'wvp-28181-2.0' into wvp-28181-2.0

Showing 47 changed files with 759 additions and 548 deletions
DOCKERFILE
... ... @@ -85,7 +85,7 @@ RUN echo '#!/bin/bash' > run.sh && \
85 85 echo 'nohup /opt/media/MediaServer -d -m 3 &' >> run.sh && \
86 86 echo 'cd /opt/wvp' >> run.sh && \
87 87 echo 'if [${WVP_CONFIG}]; then' >> run.sh && \
88   - echo ' java -jar *.jar --spring.confi g.location=/opt/wvp/config/application.yml --media.record-assist-port=18081 ${WVP_CONFIG}' >> run.sh && \
  88 + echo ' java -jar *.jar --spring.config.location=/opt/wvp/config/application.yml --media.record-assist-port=18081 ${WVP_CONFIG}' >> run.sh && \
89 89 echo 'else' >> run.sh && \
90 90 echo ' java -jar *.jar --spring.config.location=/opt/wvp/config/application.yml --media.record-assist-port=18081 --media.ip=127.0.0.1 --media.sdp-ip=${WVP_IP} --sip.ip=${WVP_IP} --media.stream-ip=${WVP_IP}' >> run.sh && \
91 91 echo 'fi' >> run.sh
... ...
... ... @@ -169,13 +169,6 @@
169 169 <version>1.2.73</version>
170 170 </dependency>
171 171  
172   - <!--Guava是一种基于开源的Java库-->
173   - <dependency>
174   - <groupId>com.google.guava</groupId>
175   - <artifactId>guava</artifactId>
176   - <version>30.0-jre</version>
177   - </dependency>
178   -
179 172 <!-- okhttp -->
180 173 <dependency>
181 174 <groupId>com.squareup.okhttp3</groupId>
... ... @@ -279,6 +272,9 @@
279 272 <plugin>
280 273 <groupId>pl.project13.maven</groupId>
281 274 <artifactId>git-commit-id-plugin</artifactId>
  275 + <configuration>
  276 + <offline>true</offline>
  277 + </configuration>
282 278 </plugin>
283 279  
284 280 <plugin>
... ...
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
... ... @@ -60,12 +60,9 @@ public class SipPlatformRunner implements CommandLineRunner {
60 60  
61 61 // 取消订阅
62 62 sipCommanderForPlatform.unregister(parentPlatform, null, (eventResult)->{
63   - ParentPlatform platform = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId());
64   - sipCommanderForPlatform.register(platform, null, null);
  63 + // 发送平台未注册消息
  64 + publisher.platformNotRegisterEventPublish(parentPlatform.getServerGBId());
65 65 });
66   -
67   - // 发送平台未注册消息
68   - publisher.platformNotRegisterEventPublish(parentPlatform.getServerGBId());
69 66 }
70 67 }
71 68 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamCallback.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +public interface InviteStreamCallback {
  4 + void call(InviteStreamInfo inviteStreamInfo);
  5 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamInfo.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  5 +
  6 +public class InviteStreamInfo {
  7 +
  8 + public InviteStreamInfo(MediaServerItem mediaServerItem, JSONObject response, String callId, String app, String stream) {
  9 + this.mediaServerItem = mediaServerItem;
  10 + this.response = response;
  11 + this.callId = callId;
  12 + this.app = app;
  13 + this.stream = stream;
  14 + }
  15 +
  16 + private MediaServerItem mediaServerItem;
  17 + private JSONObject response;
  18 + private String callId;
  19 + private String app;
  20 + private String stream;
  21 +
  22 + public MediaServerItem getMediaServerItem() {
  23 + return mediaServerItem;
  24 + }
  25 +
  26 + public void setMediaServerItem(MediaServerItem mediaServerItem) {
  27 + this.mediaServerItem = mediaServerItem;
  28 + }
  29 +
  30 + public JSONObject getResponse() {
  31 + return response;
  32 + }
  33 +
  34 + public void setResponse(JSONObject response) {
  35 + this.response = response;
  36 + }
  37 +
  38 + public String getCallId() {
  39 + return callId;
  40 + }
  41 +
  42 + public void setCallId(String callId) {
  43 + this.callId = callId;
  44 + }
  45 +
  46 + public String getApp() {
  47 + return app;
  48 + }
  49 +
  50 + public void setApp(String app) {
  51 + this.app = app;
  52 + }
  53 +
  54 + public String getStream() {
  55 + return stream;
  56 + }
  57 +
  58 + public void setStream(String stream) {
  59 + this.stream = stream;
  60 + }
  61 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
... ... @@ -114,6 +114,21 @@ public class ParentPlatform {
114 114 */
115 115 private String catalogId;
116 116  
  117 + /**
  118 + * 已被订阅目录信息
  119 + */
  120 + private boolean catalogSubscribe;
  121 +
  122 + /**
  123 + * 已被订阅报警信息
  124 + */
  125 + private boolean alarmSubscribe;
  126 +
  127 + /**
  128 + * 已被订阅GPS信息
  129 + */
  130 + private boolean gpsSubscribe;
  131 +
117 132 public Integer getId() {
118 133 return id;
119 134 }
... ... @@ -290,4 +305,28 @@ public class ParentPlatform {
290 305 public void setCatalogId(String catalogId) {
291 306 this.catalogId = catalogId;
292 307 }
  308 +
  309 + public boolean isCatalogSubscribe() {
  310 + return catalogSubscribe;
  311 + }
  312 +
  313 + public void setCatalogSubscribe(boolean catalogSubscribe) {
  314 + this.catalogSubscribe = catalogSubscribe;
  315 + }
  316 +
  317 + public boolean isAlarmSubscribe() {
  318 + return alarmSubscribe;
  319 + }
  320 +
  321 + public void setAlarmSubscribe(boolean alarmSubscribe) {
  322 + this.alarmSubscribe = alarmSubscribe;
  323 + }
  324 +
  325 + public boolean isGpsSubscribe() {
  326 + return gpsSubscribe;
  327 + }
  328 +
  329 + public void setGpsSubscribe(boolean gpsSubscribe) {
  330 + this.gpsSubscribe = gpsSubscribe;
  331 + }
293 332 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
... ... @@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.gb28181.bean;
2 2  
3 3 import org.springframework.stereotype.Component;
4 4  
  5 +import java.util.ArrayList;
  6 +import java.util.List;
5 7 import java.util.concurrent.ConcurrentHashMap;
6 8  
7 9 @Component
... ... @@ -34,4 +36,14 @@ public class SubscribeHolder {
34 36 public void removeMobilePositionSubscribe(String platformId) {
35 37 mobilePositionMap.remove(platformId);
36 38 }
  39 +
  40 + public List<String> getAllCatalogSubscribePlatform() {
  41 + List<String> platforms = new ArrayList<>();
  42 + if(catalogMap.size() > 0) {
  43 + for (String key : catalogMap.keySet()) {
  44 + platforms.add(catalogMap.get(key).getId());
  45 + }
  46 + }
  47 + return platforms;
  48 + }
37 49 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java
... ... @@ -14,19 +14,15 @@ public class SubscribeInfo {
14 14 public SubscribeInfo(RequestEvent evt, String id) {
15 15 this.id = id;
16 16 Request request = evt.getRequest();
17   - CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
18   - this.callId = callIdHeader.getCallId();
19   - FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
20   - this.fromTag = fromHeader.getTag();
21 17 ExpiresHeader expiresHeader = (ExpiresHeader)request.getHeader(ExpiresHeader.NAME);
22 18 this.expires = expiresHeader.getExpires();
23 19 EventHeader eventHeader = (EventHeader)request.getHeader(EventHeader.NAME);
24 20 this.eventId = eventHeader.getEventId();
25 21 this.eventType = eventHeader.getEventType();
26   - ViaHeader viaHeader = (ViaHeader)request.getHeader(ViaHeader.NAME);
27   - this.branch = viaHeader.getBranch();
28 22 this.transaction = evt.getServerTransaction();
29 23 this.dialog = evt.getDialog();
  24 + CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
  25 + this.callId = callIdHeader.getCallId();
30 26 }
31 27  
32 28 private String id;
... ... @@ -34,9 +30,6 @@ public class SubscribeInfo {
34 30 private String callId;
35 31 private String eventId;
36 32 private String eventType;
37   - private String fromTag;
38   - private String toTag;
39   - private String branch;
40 33 private ServerTransaction transaction;
41 34 private Dialog dialog;
42 35  
... ... @@ -52,18 +45,6 @@ public class SubscribeInfo {
52 45 return callId;
53 46 }
54 47  
55   - public String getFromTag() {
56   - return fromTag;
57   - }
58   -
59   - public void setToTag(String toTag) {
60   - this.toTag = toTag;
61   - }
62   -
63   - public String getToTag() {
64   - return toTag;
65   - }
66   -
67 48 public void setId(String id) {
68 49 this.id = id;
69 50 }
... ... @@ -76,10 +57,6 @@ public class SubscribeInfo {
76 57 this.callId = callId;
77 58 }
78 59  
79   - public void setFromTag(String fromTag) {
80   - this.fromTag = fromTag;
81   - }
82   -
83 60 public String getEventId() {
84 61 return eventId;
85 62 }
... ... @@ -96,14 +73,6 @@ public class SubscribeInfo {
96 73 this.eventType = eventType;
97 74 }
98 75  
99   - public String getBranch() {
100   - return branch;
101   - }
102   -
103   - public void setBranch(String branch) {
104   - this.branch = branch;
105   - }
106   -
107 76 public ServerTransaction getTransaction() {
108 77 return transaction;
109 78 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
... ... @@ -30,7 +30,7 @@ public class SipSubscribe {
30 30 // @Scheduled(fixedRate= 100 * 60 * 60 )
31 31 @Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次
32 32 public void execute(){
33   - logger.info("[定时任务] 清理过期的订阅信息");
  33 + logger.info("[定时任务] 清理过期的SIP订阅信息");
34 34 Calendar calendar = Calendar.getInstance();
35 35 calendar.setTime(new Date());
36 36 calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) - 5);
... ... @@ -49,10 +49,10 @@ public class SipSubscribe {
49 49 errorTimeSubscribes.remove(key);
50 50 }
51 51 }
52   - logger.info("okTimeSubscribes.size:{}",okTimeSubscribes.size());
53   - logger.info("okSubscribes.size:{}",okSubscribes.size());
54   - logger.info("errorTimeSubscribes.size:{}",errorTimeSubscribes.size());
55   - logger.info("errorSubscribes.size:{}",errorSubscribes.size());
  52 + logger.debug("okTimeSubscribes.size:{}",okTimeSubscribes.size());
  53 + logger.debug("okSubscribes.size:{}",okSubscribes.size());
  54 + logger.debug("errorTimeSubscribes.size:{}",errorTimeSubscribes.size());
  55 + logger.debug("errorSubscribes.size:{}",errorSubscribes.size());
56 56 }
57 57  
58 58 public interface Event {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
... ... @@ -68,8 +68,6 @@ public class OnlineEventListener implements ApplicationListener&lt;OnlineEvent&gt; {
68 68 String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetup.getServerId() + "_" + event.getDevice().getDeviceId();
69 69 Device deviceInStore = storager.queryVideoDevice(device.getDeviceId());
70 70 device.setOnline(1);
71   - // 处理上线监听
72   - storager.updateDevice(device);
73 71 switch (event.getFrom()) {
74 72 // 注册时触发的在线事件,先在redis中增加超时超时监听
75 73 case VideoManagerConstants.EVENT_ONLINE_REGISTER:
... ... @@ -98,7 +96,8 @@ public class OnlineEventListener implements ApplicationListener&lt;OnlineEvent&gt; {
98 96  
99 97 break;
100 98 }
101   -
  99 + // 处理上线监听
  100 + storager.updateDevice(device);
102 101 List<DeviceChannel> deviceChannelList = storager.queryOnlineChannelsByDeviceId(device.getDeviceId());
103 102 eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.ON);
104 103 // 上线添加订阅
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
... ... @@ -74,7 +74,7 @@ public class CatalogEventLister implements ApplicationListener&lt;CatalogEvent&gt; {
74 74 }
75 75 }else {
76 76 // 获取所用订阅
77   - List<String> platforms = redisCatchStorage.getAllSubscribePlatform();
  77 + List<String> platforms = subscribeHolder.getAllCatalogSubscribePlatform();
78 78 if (event.getDeviceChannels() != null) {
79 79 if (platforms.size() > 0) {
80 80 for (DeviceChannel deviceChannel : event.getDeviceChannels()) {
... ... @@ -117,8 +117,6 @@ public class CatalogEventLister implements ApplicationListener&lt;CatalogEvent&gt; {
117 117 List<ParentPlatform> parentPlatforms = parentPlatformMap.get(gbId);
118 118 if (parentPlatforms != null && parentPlatforms.size() > 0) {
119 119 for (ParentPlatform platform : parentPlatforms) {
120   - String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_" + platform.getServerGBId();
121   -// SubscribeInfo subscribeInfo = redisCatchStorage.getSubscribe(key);
122 120 SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(platform.getServerGBId());
123 121 if (subscribeInfo == null) continue;
124 122 logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId);
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
... ... @@ -95,14 +95,14 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
95 95 logger.debug("\n收到响应:\n{}", responseEvent.getResponse());
96 96 int status = response.getStatusCode();
97 97  
98   - if (((status >= 200) && (status < 300)) || status == 401) { // Success!
  98 + if (((status >= 200) && (status < 300)) || status == Response.UNAUTHORIZED) { // Success!
99 99 CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME);
100 100 String method = cseqHeader.getMethod();
101 101 ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method);
102 102 if (sipRequestProcessor != null) {
103 103 sipRequestProcessor.process(responseEvent);
104 104 }
105   - if (responseEvent.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) {
  105 + if (status != Response.UNAUTHORIZED && responseEvent.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) {
106 106 CallIdHeader callIdHeader = (CallIdHeader)responseEvent.getResponse().getHeader(CallIdHeader.NAME);
107 107 if (callIdHeader != null) {
108 108 SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId());
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
... ... @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
2 2  
3 3 import com.genersoft.iot.vmp.common.StreamInfo;
4 4 import com.genersoft.iot.vmp.gb28181.bean.Device;
  5 +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
5 6 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6 7 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
7 8 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
... ... @@ -103,7 +104,7 @@ public interface ISIPCommander {
103 104 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
104 105 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
105 106 */
106   - void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
  107 + void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event errorEvent);
107 108  
108 109 /**
109 110 * 请求历史媒体下载
... ... @@ -114,13 +115,13 @@ public interface ISIPCommander {
114 115 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
115 116 * @param downloadSpeed 下载倍速参数
116 117 */
117   - void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
  118 + void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, InviteStreamCallback event, SipSubscribe.Event errorEvent);
118 119  
119 120 /**
120 121 * 视频流停止
121 122 */
122   - void streamByeCmd(String deviceId, String channelId, String stream, SipSubscribe.Event okEvent);
123   - void streamByeCmd(String deviceId, String channelId, String stream);
  123 + void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent);
  124 + void streamByeCmd(String deviceId, String channelId, String stream, String callId);
124 125  
125 126 /**
126 127 * 回放暂停
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
... ... @@ -6,6 +6,8 @@ import com.genersoft.iot.vmp.conf.DynamicTask;
6 6 import com.genersoft.iot.vmp.conf.SipConfig;
7 7 import com.genersoft.iot.vmp.conf.UserSetup;
8 8 import com.genersoft.iot.vmp.gb28181.bean.Device;
  9 +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
  10 +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo;
9 11 import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
10 12 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
11 13 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
... ... @@ -445,27 +447,13 @@ public class SIPCommander implements ISIPCommander {
445 447 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
446 448 */
447 449 @Override
448   - public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
449   - , SipSubscribe.Event errorEvent) {
  450 + public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  451 + String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
  452 + SipSubscribe.Event errorEvent) {
450 453 try {
451 454  
452 455 logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
453 456  
454   - // 添加订阅
455   - JSONObject subscribeKey = new JSONObject();
456   - subscribeKey.put("app", "rtp");
457   - subscribeKey.put("stream", ssrcInfo.getStream());
458   - subscribeKey.put("regist", true);
459   - subscribeKey.put("schema", "rtmp");
460   - subscribeKey.put("mediaServerId", mediaServerItem.getId());
461   - logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
462   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
463   - (MediaServerItem mediaServerItemInUse, JSONObject json)->{
464   - if (event != null) {
465   - event.response(mediaServerItemInUse, json);
466   - }
467   - });
468   -
469 457 StringBuffer content = new StringBuffer(200);
470 458 content.append("v=0\r\n");
471 459 content.append("o="+sipConfig.getId()+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
... ... @@ -530,6 +518,21 @@ public class SIPCommander implements ISIPCommander {
530 518 CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
531 519 : udpSipProvider.getNewCallId();
532 520  
  521 + // 添加订阅
  522 + JSONObject subscribeKey = new JSONObject();
  523 + subscribeKey.put("app", "rtp");
  524 + subscribeKey.put("stream", ssrcInfo.getStream());
  525 + subscribeKey.put("regist", true);
  526 + subscribeKey.put("schema", "rtmp");
  527 + subscribeKey.put("mediaServerId", mediaServerItem.getId());
  528 + logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey);
  529 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  530 + (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  531 + if (hookEvent != null) {
  532 + InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream());
  533 + hookEvent.call(inviteStreamInfo);
  534 + }
  535 + });
533 536 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
534 537  
535 538 transmitRequest(device, request, errorEvent, okEvent -> {
... ... @@ -537,6 +540,9 @@ public class SIPCommander implements ISIPCommander {
537 540 streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction());
538 541 streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
539 542 });
  543 + if (inviteStreamCallback != null) {
  544 + inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
  545 + }
540 546 } catch ( SipException | ParseException | InvalidArgumentException e) {
541 547 e.printStackTrace();
542 548 }
... ... @@ -552,24 +558,11 @@ public class SIPCommander implements ISIPCommander {
552 558 * @param downloadSpeed 下载倍速参数
553 559 */
554 560 @Override
555   - public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event
  561 + public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, InviteStreamCallback event
556 562 , SipSubscribe.Event errorEvent) {
557 563 try {
558 564 logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
559 565  
560   - // 添加订阅
561   - JSONObject subscribeKey = new JSONObject();
562   - subscribeKey.put("app", "rtp");
563   - subscribeKey.put("stream", ssrcInfo.getStream());
564   - subscribeKey.put("regist", true);
565   - subscribeKey.put("mediaServerId", mediaServerItem.getId());
566   - logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
567   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
568   - (MediaServerItem mediaServerItemInUse, JSONObject json)->{
569   - event.response(mediaServerItemInUse, json);
570   - subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
571   - });
572   -
573 566 StringBuffer content = new StringBuffer(200);
574 567 content.append("v=0\r\n");
575 568 content.append("o="+sipConfig.getId()+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
... ... @@ -637,6 +630,19 @@ public class SIPCommander implements ISIPCommander {
637 630 CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
638 631 : udpSipProvider.getNewCallId();
639 632  
  633 + // 添加订阅
  634 + JSONObject subscribeKey = new JSONObject();
  635 + subscribeKey.put("app", "rtp");
  636 + subscribeKey.put("stream", ssrcInfo.getStream());
  637 + subscribeKey.put("regist", true);
  638 + subscribeKey.put("mediaServerId", mediaServerItem.getId());
  639 + logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
  640 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  641 + (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  642 + event.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
  643 + subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
  644 + });
  645 +
640 646 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
641 647  
642 648 ClientTransaction transaction = transmitRequest(device, request, errorEvent);
... ... @@ -652,15 +658,15 @@ public class SIPCommander implements ISIPCommander {
652 658 * 视频流停止, 不使用回调
653 659 */
654 660 @Override
655   - public void streamByeCmd(String deviceId, String channelId, String stream) {
656   - streamByeCmd(deviceId, channelId, stream, null);
  661 + public void streamByeCmd(String deviceId, String channelId, String stream, String callId) {
  662 + streamByeCmd(deviceId, channelId, stream, callId, null);
657 663 }
658 664  
659 665 /**
660 666 * 视频流停止
661 667 */
662 668 @Override
663   - public void streamByeCmd(String deviceId, String channelId, String stream, SipSubscribe.Event okEvent) {
  669 + public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) {
664 670 try {
665 671 SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, null, stream);
666 672 ClientTransaction transaction = streamSession.getTransactionByStream(deviceId, channelId, stream);
... ... @@ -672,7 +678,15 @@ public class SIPCommander implements ISIPCommander {
672 678 }
673 679 return;
674 680 }
675   - SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, stream);
  681 + SIPDialog dialog;
  682 + if (callId != null) {
  683 + dialog = streamSession.getDialogByCallId(deviceId, channelId, callId);
  684 + }else {
  685 + if (stream == null) return;
  686 + dialog = streamSession.getDialogByStream(deviceId, channelId, stream);
  687 + }
  688 +
  689 +
676 690 if (dialog == null) {
677 691 logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId);
678 692 return;
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
... ... @@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
13 13 import com.genersoft.iot.vmp.utils.SerializeUtils;
14 14 import gov.nist.javax.sip.SipProviderImpl;
15 15 import gov.nist.javax.sip.SipStackImpl;
  16 +import gov.nist.javax.sip.message.MessageFactoryImpl;
16 17 import gov.nist.javax.sip.message.SIPRequest;
17 18 import gov.nist.javax.sip.stack.SIPDialog;
18 19 import org.slf4j.Logger;
... ... @@ -77,11 +78,11 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
77 78 @Override
78 79 public boolean unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) {
79 80 ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
  81 + parentPlatform.setExpires("0");
80 82 if (parentPlatformCatch != null) {
81 83 parentPlatformCatch.setParentPlatform(parentPlatform);
82 84 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
83 85 }
84   - parentPlatform.setExpires("0");
85 86 return register(parentPlatform, null, null, errorEvent, okEvent, false);
86 87 }
87 88  
... ... @@ -101,7 +102,9 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
101 102 callIdHeader = udpSipProvider.getNewCallId();
102 103 }
103 104  
104   - request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(Request.REGISTER), "FromRegister" + tm, null, callIdHeader);
  105 + request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform,
  106 + redisCatchStorage.getCSEQ(Request.REGISTER), "FromRegister" + tm,
  107 + "z9hG4bK-" + UUID.randomUUID().toString().replace("-", ""), callIdHeader);
105 108 // 将 callid 写入缓存, 等注册成功可以更新状态
106 109 String callIdFromHeader = callIdHeader.getCallId();
107 110 redisCatchStorage.updatePlatformRegisterInfo(callIdFromHeader, parentPlatform.getServerGBId());
... ... @@ -414,11 +417,13 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
414 417 private void sendNotify(ParentPlatform parentPlatform, String catalogXmlContent,
415 418 SubscribeInfo subscribeInfo, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent )
416 419 throws NoSuchFieldException, IllegalAccessException, SipException, ParseException {
  420 + MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory();
  421 + // 设置编码, 防止中文乱码
  422 + messageFactory.setDefaultContentEncodingCharset("gb2312");
417 423 Dialog dialog = subscribeInfo.getDialog();
418   - Request notifyRequest = dialog.createRequest(Request.NOTIFY);
419   -
  424 + if (dialog == null) return;
  425 + SIPRequest notifyRequest = (SIPRequest)dialog.createRequest(Request.NOTIFY);
420 426 ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
421   -
422 427 notifyRequest.setContent(catalogXmlContent, contentTypeHeader);
423 428  
424 429 SubscriptionStateHeader subscriptionState = sipFactory.createHeaderFactory()
... ... @@ -509,7 +514,8 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
509 514 }
510 515  
511 516 @Override
512   - public boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index) {
  517 + public boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels,
  518 + SubscribeInfo subscribeInfo, Integer index) {
513 519 if (parentPlatform == null
514 520 || deviceChannels == null
515 521 || deviceChannels.size() == 0
... ... @@ -577,24 +583,30 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
577 583 recordXml.append("<SN>" +recordInfo.getSn() + "</SN>\r\n");
578 584 recordXml.append("<DeviceID>" + recordInfo.getDeviceId() + "</DeviceID>\r\n");
579 585 recordXml.append("<SumNum>" + recordInfo.getSumNum() + "</SumNum>\r\n");
580   - recordXml.append("<RecordList Num=\"" + recordInfo.getRecordList().size()+"\">\r\n");
581   - for (RecordItem recordItem : recordInfo.getRecordList()) {
582   - recordXml.append("<Item>\r\n");
583   - if (deviceChannel != null) {
584   - recordXml.append("<DeviceID>" + recordItem.getDeviceId() + "</DeviceID>\r\n");
585   - recordXml.append("<Name>" + recordItem.getName() + "</Name>\r\n");
586   - recordXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n");
587   - recordXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n");
588   - recordXml.append("<Secrecy>" + recordItem.getSecrecy() + "</Secrecy>\r\n");
589   - recordXml.append("<Type>" + recordItem.getType() + "</Type>\r\n");
590   - if (!StringUtils.isEmpty(recordItem.getFileSize())) {
591   - recordXml.append("<FileSize>" + recordItem.getFileSize() + "</FileSize>\r\n");
592   - }
593   - if (!StringUtils.isEmpty(recordItem.getFilePath())) {
594   - recordXml.append("<FilePath>" + recordItem.getFilePath() + "</FilePath>\r\n");
  586 + if (recordInfo.getRecordList() == null ) {
  587 + recordXml.append("<RecordList Num=\"0\">\r\n");
  588 + }else {
  589 + recordXml.append("<RecordList Num=\"" + recordInfo.getRecordList().size()+"\">\r\n");
  590 + if (recordInfo.getRecordList().size() > 0) {
  591 + for (RecordItem recordItem : recordInfo.getRecordList()) {
  592 + recordXml.append("<Item>\r\n");
  593 + if (deviceChannel != null) {
  594 + recordXml.append("<DeviceID>" + recordItem.getDeviceId() + "</DeviceID>\r\n");
  595 + recordXml.append("<Name>" + recordItem.getName() + "</Name>\r\n");
  596 + recordXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n");
  597 + recordXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n");
  598 + recordXml.append("<Secrecy>" + recordItem.getSecrecy() + "</Secrecy>\r\n");
  599 + recordXml.append("<Type>" + recordItem.getType() + "</Type>\r\n");
  600 + if (!StringUtils.isEmpty(recordItem.getFileSize())) {
  601 + recordXml.append("<FileSize>" + recordItem.getFileSize() + "</FileSize>\r\n");
  602 + }
  603 + if (!StringUtils.isEmpty(recordItem.getFilePath())) {
  604 + recordXml.append("<FilePath>" + recordItem.getFilePath() + "</FilePath>\r\n");
  605 + }
  606 + }
  607 + recordXml.append("</Item>\r\n");
595 608 }
596 609 }
597   - recordXml.append("</Item>\r\n");
598 610 }
599 611  
600 612 recordXml.append("</RecordList>\r\n");
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
... ... @@ -27,10 +27,7 @@ import javax.sip.header.CallIdHeader;
27 27 import javax.sip.header.FromHeader;
28 28 import javax.sip.header.HeaderAddress;
29 29 import javax.sip.header.ToHeader;
30   -import java.util.HashMap;
31   -import java.util.Map;
32   -import java.util.Timer;
33   -import java.util.TimerTask;
  30 +import java.util.*;
34 31  
35 32 /**
36 33 * SIP命令类型: ACK请求
... ... @@ -84,44 +81,72 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
84 81 String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
85 82 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId, null, callIdHeader.getCallId());
86 83 String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
87   - String deviceId = sendRtpItem.getDeviceId();
88   - StreamInfo streamInfo = null;
89   - if (sendRtpItem.isPlay()) {
90   - streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
91   - }else {
92   - streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId);
93   - }
94   - if (streamInfo == null) {
95   - streamInfo = new StreamInfo();
96   - streamInfo.setApp(sendRtpItem.getApp());
97   - streamInfo.setStream(sendRtpItem.getStreamId());
98   - }
99   - redisCatchStorage.updateSendRTPSever(sendRtpItem);
  84 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  85 + logger.info("收到ACK,开始向上级推流 rtp/{}", sendRtpItem.getStreamId());
100 86 Map<String, Object> param = new HashMap<>();
101 87 param.put("vhost","__defaultVhost__");
102   - param.put("app",streamInfo.getApp());
103   - param.put("stream",streamInfo.getStream());
  88 + param.put("app",sendRtpItem.getApp());
  89 + param.put("stream",sendRtpItem.getStreamId());
104 90 param.put("ssrc", sendRtpItem.getSsrc());
105 91 param.put("dst_url",sendRtpItem.getIp());
106 92 param.put("dst_port", sendRtpItem.getPort());
107 93 param.put("is_udp", is_Udp);
108   - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
109   - JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
110   - if (jsonObject.getInteger("code") != 0) {
111   - logger.info("监听流以等待流上线{}/{}", streamInfo.getApp(), streamInfo.getStream());
112   - // 监听流上线
113   - // 添加订阅
114   - JSONObject subscribeKey = new JSONObject();
115   - subscribeKey.put("app", "rtp");
116   - subscribeKey.put("stream", streamInfo.getStream());
117   - subscribeKey.put("regist", true);
118   - subscribeKey.put("schema", "rtmp");
119   - subscribeKey.put("mediaServerId", sendRtpItem.getMediaServerId());
120   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
121   - (MediaServerItem mediaServerItemInUse, JSONObject json)->{
122   - zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
123   - });
124   - }
  94 + param.put("src_port", sendRtpItem.getLocalPort());
  95 + zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  96 +
  97 +
  98 +
  99 +// if (streamInfo == null) { // 流还没上来,对方就回复ack
  100 +// logger.info("监听流以等待流上线1 rtp/{}", sendRtpItem.getStreamId());
  101 +// // 监听流上线
  102 +// // 添加订阅
  103 +// JSONObject subscribeKey = new JSONObject();
  104 +// subscribeKey.put("app", "rtp");
  105 +// subscribeKey.put("stream", sendRtpItem.getStreamId());
  106 +// subscribeKey.put("regist", true);
  107 +// subscribeKey.put("schema", "rtmp");
  108 +// subscribeKey.put("mediaServerId", sendRtpItem.getMediaServerId());
  109 +// subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  110 +// (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  111 +// Map<String, Object> param = new HashMap<>();
  112 +// param.put("vhost","__defaultVhost__");
  113 +// param.put("app",json.getString("app"));
  114 +// param.put("stream",json.getString("stream"));
  115 +// param.put("ssrc", sendRtpItem.getSsrc());
  116 +// param.put("dst_url",sendRtpItem.getIp());
  117 +// param.put("dst_port", sendRtpItem.getPort());
  118 +// param.put("is_udp", is_Udp);
  119 +// param.put("src_port", sendRtpItem.getLocalPort());
  120 +// zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  121 +// });
  122 +// }else {
  123 +// Map<String, Object> param = new HashMap<>();
  124 +// param.put("vhost","__defaultVhost__");
  125 +// param.put("app",streamInfo.getApp());
  126 +// param.put("stream",streamInfo.getStream());
  127 +// param.put("ssrc", sendRtpItem.getSsrc());
  128 +// param.put("dst_url",sendRtpItem.getIp());
  129 +// param.put("dst_port", sendRtpItem.getPort());
  130 +// param.put("is_udp", is_Udp);
  131 +// param.put("src_port", sendRtpItem.getLocalPort());
  132 +//
  133 +// JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  134 +// if (jsonObject.getInteger("code") != 0) {
  135 +// logger.info("监听流以等待流上线2 {}/{}", streamInfo.getApp(), streamInfo.getStream());
  136 +// // 监听流上线
  137 +// // 添加订阅
  138 +// JSONObject subscribeKey = new JSONObject();
  139 +// subscribeKey.put("app", "rtp");
  140 +// subscribeKey.put("stream", streamInfo.getStream());
  141 +// subscribeKey.put("regist", true);
  142 +// subscribeKey.put("schema", "rtmp");
  143 +// subscribeKey.put("mediaServerId", sendRtpItem.getMediaServerId());
  144 +// subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  145 +// (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  146 +// zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  147 +// });
  148 +// }
  149 +// }
125 150 }
126 151 }
127 152 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
... ... @@ -93,14 +93,16 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
93 93 param.put("app",sendRtpItem.getApp());
94 94 param.put("stream",streamId);
95 95 param.put("ssrc",sendRtpItem.getSsrc());
96   - logger.info("停止向上级推流:" + streamId);
  96 + logger.info("收到bye:停止向上级推流:" + streamId);
97 97 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
98 98 zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
99 99 redisCatchStorage.deleteSendRTPServer(platformGbId, channelId, callIdHeader.getCallId(), null);
100 100 int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId);
101 101 if (totalReaderCount <= 0) {
102   - logger.info(streamId + "无其它观看者,通知设备停止推流");
103   - cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId);
  102 + logger.info("收到bye: {}无其它观看者,通知设备停止推流", streamId);
  103 + if (sendRtpItem.isPlay()) {
  104 + cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId, null);
  105 + }
104 106 }
105 107 }
106 108 // 可能是设备主动停止
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
... ... @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.common.StreamInfo;
6 6 import com.genersoft.iot.vmp.conf.DynamicTask;
7 7 import com.genersoft.iot.vmp.gb28181.bean.*;
8 8 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  9 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
9 10 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
10 11 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
11 12 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
... ... @@ -91,6 +92,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
91 92 @Autowired
92 93 private SIPProcessorObserver sipProcessorObserver;
93 94  
  95 + @Autowired
  96 + private VideoStreamSessionManager sessionManager;
  97 +
94 98  
95 99 @Override
96 100 public void afterPropertiesSet() throws Exception {
... ... @@ -233,6 +237,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
233 237 }
234 238 String username = sdp.getOrigin().getUsername();
235 239 String addressStr = sdp.getOrigin().getAddress();
  240 +
236 241 logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc);
237 242 Device device = null;
238 243 // 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标
... ... @@ -266,13 +271,14 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
266 271 sendRtpItem.setDialog(dialogByteArray);
267 272 byte[] transactionByteArray = SerializeUtils.serialize(evt.getServerTransaction());
268 273 sendRtpItem.setTransaction(transactionByteArray);
269   - // 写入redis, 超时时回复
270   - redisCatchStorage.updateSendRTPSever(sendRtpItem);
  274 +
271 275  
272 276 Long finalStartTime = startTime;
273 277 Long finalStopTime = stopTime;
274 278 ZLMHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON)->{
275   - logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", sendRtpItem.getApp(), sendRtpItem.getStreamId());
  279 + String app = responseJSON.getString("app");
  280 + String stream = responseJSON.getString("stream");
  281 + logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", app, stream);
276 282 // * 0 等待设备推流上来
277 283 // * 1 下级已经推流,等待上级平台回复ack
278 284 // * 2 推流中
... ... @@ -325,46 +331,66 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
325 331 e.printStackTrace();
326 332 }
327 333 });
  334 + sendRtpItem.setApp("rtp");
328 335 if ("Playback".equals(sessionName)) {
329 336 sendRtpItem.setPlay(false);
330   - sendRtpItem.setStreamId(ssrc);
  337 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, true);
  338 + sendRtpItem.setStreamId(ssrcInfo.getStream());
  339 + // 写入redis, 超时时回复
  340 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
331 341 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
332   - playService.playBack(device.getDeviceId(), channelId, format.format(start), format.format(end),result -> {
333   - if (result.getCode() != 0){
334   - logger.warn("录像回放失败");
335   - if (result.getEvent() != null) {
336   - errorEvent.response(result.getEvent());
337   - }
338   - redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
339   - try {
340   - responseAck(evt, Response.REQUEST_TIMEOUT);
341   - } catch (SipException e) {
342   - e.printStackTrace();
343   - } catch (InvalidArgumentException e) {
344   - e.printStackTrace();
345   - } catch (ParseException e) {
346   - e.printStackTrace();
  342 + playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, format.format(start),
  343 + format.format(end), null, result -> {
  344 + if (result.getCode() != 0){
  345 + logger.warn("录像回放失败");
  346 + if (result.getEvent() != null) {
  347 + errorEvent.response(result.getEvent());
  348 + }
  349 + redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
  350 + try {
  351 + responseAck(evt, Response.REQUEST_TIMEOUT);
  352 + } catch (SipException e) {
  353 + e.printStackTrace();
  354 + } catch (InvalidArgumentException e) {
  355 + e.printStackTrace();
  356 + } catch (ParseException e) {
  357 + e.printStackTrace();
  358 + }
  359 + }else {
  360 + if (result.getMediaServerItem() != null) {
  361 + hookEvent.response(result.getMediaServerItem(), result.getResponse());
  362 + }
347 363 }
348   - }else {
349   - if (result.getMediaServerItem() != null) {
350   - hookEvent.response(result.getMediaServerItem(), result.getResponse());
351   - }
352   - }
353   - });
  364 + });
354 365 }else {
355 366 sendRtpItem.setPlay(true);
356   - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
357   - if (streamInfo == null) {
  367 + SsrcTransaction playTransaction = sessionManager.getSsrcTransaction(device.getDeviceId(), channelId, "play", null);
  368 + if (playTransaction != null) {
  369 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, "rtp", playTransaction.getStream());
  370 + if (!streamReady) {
  371 + playTransaction = null;
  372 + }
  373 + }
  374 + if (playTransaction == null) {
  375 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, true);
358 376 if (mediaServerItem.isRtpEnable()) {
359 377 sendRtpItem.setStreamId(String.format("%s_%s", device.getDeviceId(), channelId));
  378 + }else {
  379 + sendRtpItem.setStreamId(ssrcInfo.getStream());
360 380 }
361   - sendRtpItem.setPlay(false);
362   - playService.play(mediaServerItem,device.getDeviceId(), channelId, hookEvent, errorEvent, ()->{
  381 + // 写入redis, 超时时回复
  382 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  383 + playService.play(mediaServerItem, ssrcInfo, device, channelId, hookEvent, errorEvent, (code, msg)->{
363 384 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
364   - });
  385 + }, null);
365 386 }else {
366   - sendRtpItem.setStreamId(streamInfo.getStream());
367   - hookEvent.response(mediaServerItem, null);
  387 + sendRtpItem.setStreamId(playTransaction.getStream());
  388 + // 写入redis, 超时时回复
  389 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  390 + JSONObject jsonObject = new JSONObject();
  391 + jsonObject.put("app", sendRtpItem.getApp());
  392 + jsonObject.put("stream", sendRtpItem.getStreamId());
  393 + hookEvent.response(mediaServerItem, jsonObject);
368 394 }
369 395 }
370 396 }else if (gbStream != null) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
... ... @@ -233,7 +233,6 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
233 233 */
234 234 private void processNotifyCatalogList(RequestEvent evt) {
235 235 try {
236   - System.out.println(343434);
237 236 FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
238 237 String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader);
239 238  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
... ... @@ -158,20 +158,14 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
158 158 String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔
159 159 dynamicTask.startCron(key, new GPSSubscribeTask(redisCatchStorage, sipCommanderForPlatform, storager, platformId, sn, key, subscribeHolder), Integer.parseInt(interval));
160 160 subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
161   -// redisCatchStorage.updateSubscribe(key, subscribeInfo);
162 161 }else if (subscribeInfo.getExpires() == 0) {
163 162 dynamicTask.stop(key);
164   -// redisCatchStorage.delSubscribe(key);
165 163 subscribeHolder.removeMobilePositionSubscribe(platformId);
166 164 }
167 165  
168 166 try {
169 167 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId);
170   - Response response = responseXmlAck(evt, resultXml.toString(), parentPlatform);
171   - ToHeader toHeader = (ToHeader)response.getHeader(ToHeader.NAME);
172   - subscribeInfo.setToTag(toHeader.getTag());
173   - redisCatchStorage.updateSubscribe(key, subscribeInfo);
174   -
  168 + responseXmlAck(evt, resultXml.toString(), parentPlatform);
175 169 } catch (SipException e) {
176 170 e.printStackTrace();
177 171 } catch (InvalidArgumentException e) {
... ... @@ -211,21 +205,14 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
211 205 .append("</Response>\r\n");
212 206  
213 207 if (subscribeInfo.getExpires() > 0) {
214   -// redisCatchStorage.updateSubscribe(key, subscribeInfo);
215 208 subscribeHolder.putCatalogSubscribe(platformId, subscribeInfo);
216 209 }else if (subscribeInfo.getExpires() == 0) {
217   -// redisCatchStorage.delSubscribe(key);
218 210 subscribeHolder.removeCatalogSubscribe(platformId);
219 211 }
220 212  
221 213 try {
222 214 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId);
223   - Response response = responseXmlAck(evt, resultXml.toString(), parentPlatform);
224   - ToHeader toHeader = (ToHeader)response.getHeader(ToHeader.NAME);
225   - subscribeInfo.setToTag(toHeader.getTag());
226   -// redisCatchStorage.updateSubscribe(key, subscribeInfo);
227   - subscribeHolder.putCatalogSubscribe(platformId, subscribeInfo);
228   -
  215 + responseXmlAck(evt, resultXml.toString(), parentPlatform);
229 216 } catch (SipException e) {
230 217 e.printStackTrace();
231 218 } catch (InvalidArgumentException e) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
... ... @@ -67,9 +67,6 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
67 67 // 查询设备是否存在
68 68 CSeqHeader cseqHeader = (CSeqHeader) evt.getRequest().getHeader(CSeqHeader.NAME);
69 69 String method = cseqHeader.getMethod();
70   - if (method.equals("MESSAGE")) {
71   - System.out.println();
72   - }
73 70 Device device = redisCatchStorage.getDevice(deviceId);
74 71 // 查询上级平台是否存在
75 72 ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId);
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
... ... @@ -18,6 +18,7 @@ import org.springframework.stereotype.Component;
18 18 import javax.sip.InvalidArgumentException;
19 19 import javax.sip.RequestEvent;
20 20 import javax.sip.SipException;
  21 +import javax.sip.header.CallIdHeader;
21 22 import javax.sip.message.Response;
22 23 import java.text.ParseException;
23 24  
... ... @@ -56,14 +57,15 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
56 57 } catch (ParseException e) {
57 58 e.printStackTrace();
58 59 }
  60 + CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
59 61 String NotifyType =getText(rootElement, "NotifyType");
60 62 if (NotifyType.equals("121")){
61 63 logger.info("媒体播放完毕,通知关流");
62   - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(device.getDeviceId(), "*");
63   - if (streamInfo != null) {
64   - redisCatchStorage.stopPlayback(streamInfo);
65   - cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream());
66   - }
  64 + String channelId =getText(rootElement, "DeviceID");
  65 + redisCatchStorage.stopPlayback(device.getDeviceId(), channelId, null, callIdHeader.getCallId());
  66 + cmder.streamByeCmd(device.getDeviceId(), channelId, null, callIdHeader.getCallId());
  67 + // TODO 如果级联播放,需要给上级发送此通知
  68 +
67 69 }
68 70 }
69 71  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java
... ... @@ -88,7 +88,7 @@ public class RecordInfoQueryMessageHandler extends SIPRequestProcessorParent imp
88 88 Element secrecyElement = rootElement.element("Secrecy");
89 89 int secrecy = 0;
90 90 if (secrecyElement != null) {
91   - secrecy = Integer.parseInt(secrecyElement.getText());
  91 + secrecy = Integer.parseInt(secrecyElement.getText().trim());
92 92 }
93 93 String type = "all";
94 94 Element typeElement = rootElement.element("Type");
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java
... ... @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
4 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
  5 +import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
5 6 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
6 7 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
7 8 import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract;
... ... @@ -40,6 +41,9 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
40 41 @Autowired
41 42 private SIPProcessorObserver sipProcessorObserver;
42 43  
  44 + @Autowired
  45 + private SubscribeHolder subscribeHolder;
  46 +
43 47 @Override
44 48 public void afterPropertiesSet() throws Exception {
45 49 // 添加消息处理的订阅
... ... @@ -83,19 +87,19 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
83 87 // 注册/注销成功
84 88 logger.info(String.format("%s %s成功", platformGBId, action));
85 89 redisCatchStorage.delPlatformRegisterInfo(callId);
86   - parentPlatform.setStatus("注册".equals(action));
  90 + redisCatchStorage.delPlatformCatchInfo(platformGBId);
87 91 // 取回Expires设置,避免注销过程中被置为0
88   - if (!parentPlatformCatch.getParentPlatform().getExpires().equals("0")) {
89   - ParentPlatform parentPlatformTmp = storager.queryParentPlatByServerGBId(platformGBId);
90   - String expires = parentPlatformTmp.getExpires();
91   - parentPlatform.setExpires(expires);
92   - parentPlatform.setId(parentPlatformTmp.getId());
93   - redisCatchStorage.updatePlatformRegister(parentPlatform);
94   - redisCatchStorage.updatePlatformKeepalive(parentPlatform);
95   - parentPlatformCatch.setParentPlatform(parentPlatform);
96   - redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
97   - }
  92 + ParentPlatform parentPlatformTmp = storager.queryParentPlatByServerGBId(platformGBId);
  93 + parentPlatformTmp.setStatus("注册".equals(action));
  94 + redisCatchStorage.updatePlatformRegister(parentPlatformTmp);
  95 + redisCatchStorage.updatePlatformKeepalive(parentPlatformTmp);
  96 + parentPlatformCatch.setParentPlatform(parentPlatformTmp);
  97 + redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
98 98 storager.updateParentPlatformStatus(platformGBId, "注册".equals(action));
  99 + if ("注销".equals(action)) {
  100 + subscribeHolder.removeCatalogSubscribe(platformGBId);
  101 + subscribeHolder.removeMobilePositionSubscribe(platformGBId);
  102 + }
99 103  
100 104 }
101 105 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -9,9 +9,12 @@ import com.genersoft.iot.vmp.common.StreamInfo;
9 9 import com.genersoft.iot.vmp.conf.MediaConfig;
10 10 import com.genersoft.iot.vmp.conf.UserSetup;
11 11 import com.genersoft.iot.vmp.gb28181.bean.Device;
  12 +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
12 13 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
  14 +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
13 15 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
14 16 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
  17 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
15 18 import com.genersoft.iot.vmp.media.zlm.dto.*;
16 19 import com.genersoft.iot.vmp.service.*;
17 20 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
... ... @@ -81,7 +84,7 @@ public class ZLMHttpHookListener {
81 84 private UserSetup userSetup;
82 85  
83 86 @Autowired
84   - private MediaConfig mediaConfig;
  87 + private VideoStreamSessionManager sessionManager;
85 88  
86 89 @Autowired
87 90 private ZLMRESTfulUtils zlmresTfulUtils;
... ... @@ -207,15 +210,15 @@ public class ZLMHttpHookListener {
207 210 }else {
208 211 ret.put("enableMP4", userSetup.isRecordPushLive());
209 212 }
210   - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(stream);
211   -
212   - // 录像回放时不进行录像下载
213   - if (streamInfo != null) {
214   - ret.put("enableMP4", false);
215   - }else {
216   - ret.put("enableMP4", userSetup.isRecordPushLive());
  213 + List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, stream);
  214 + if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) {
  215 + String deviceId = ssrcTransactionForAll.get(0).getDeviceId();
  216 + String channelId = ssrcTransactionForAll.get(0).getChannelId();
  217 + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
  218 + if (deviceChannel != null) {
  219 + ret.put("enable_audio", deviceChannel.isHasAudio());
  220 + }
217 221 }
218   -
219 222 return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
220 223 }
221 224  
... ... @@ -350,8 +353,12 @@ public class ZLMHttpHookListener {
350 353 redisCatchStorage.stopPlay(streamInfo);
351 354 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
352 355 }else{
353   - streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId);
354   - redisCatchStorage.stopPlayback(streamInfo);
  356 + streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
  357 + if (streamInfo != null) {
  358 + redisCatchStorage.stopPlayback(streamInfo.getDeviceID(), streamInfo.getChannelId(),
  359 + streamInfo.getStream(), null);
  360 + }
  361 +
355 362 }
356 363 }else {
357 364 if (!"rtp".equals(app)){
... ... @@ -443,18 +450,19 @@ public class ZLMHttpHookListener {
443 450 ret.put("close", false);
444 451 } else {
445 452 cmder.streamByeCmd(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId(),
446   - streamInfoForPlayCatch.getStream());
  453 + streamInfoForPlayCatch.getStream(), null);
447 454 redisCatchStorage.stopPlay(streamInfoForPlayCatch);
448 455 storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId());
449 456 }
450 457 }else{
451   - StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlaybackByStreamId(streamId);
  458 + StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, streamId, null);
452 459 if (streamInfoForPlayBackCatch != null) {
453 460 cmder.streamByeCmd(streamInfoForPlayBackCatch.getDeviceID(),
454   - streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream());
455   - redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch);
  461 + streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null);
  462 + redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(),
  463 + streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null);
456 464 }else {
457   - StreamInfo streamInfoForDownload = redisCatchStorage.queryDownloadByStreamId(streamId);
  465 + StreamInfo streamInfoForDownload = redisCatchStorage.queryDownload(null, null, streamId, null);
458 466 // 进行录像下载时无人观看不断流
459 467 if (streamInfoForDownload != null) {
460 468 ret.put("close", false);
... ... @@ -462,7 +470,7 @@ public class ZLMHttpHookListener {
462 470 }
463 471 }
464 472 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
465   - if (mediaServerItem != null && "-1".equals(mediaServerItem.getStreamNoneReaderDelayMS())) {
  473 + if (mediaServerItem != null && mediaServerItem.getStreamNoneReaderDelayMS() == -1) {
466 474 ret.put("close", false);
467 475 }
468 476 return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
... ... @@ -45,12 +45,8 @@ public class ZLMRTPServerFactory {
45 45  
46 46 Map<String, Object> param = new HashMap<>();
47 47 int result = -1;
48   - /**
49   - * 不设置推流端口端则使用随机端口
50   - */
51   - if (StringUtils.isEmpty(mediaServerItem.getSendRtpPortRange())){
52   - param.put("port", 0);
53   - }else {
  48 + // 不设置推流端口端则使用随机端口
  49 + if (!StringUtils.isEmpty(mediaServerItem.getSendRtpPortRange())){
54 50 int newPort = getPortFromportRange(mediaServerItem);
55 51 param.put("port", newPort);
56 52 }
... ...
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
... ... @@ -2,10 +2,14 @@ package com.genersoft.iot.vmp.service;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
4 4 import com.genersoft.iot.vmp.gb28181.bean.Device;
  5 +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
  6 +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo;
5 7 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6 8 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
7 9 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  10 +import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;
8 11 import com.genersoft.iot.vmp.service.bean.PlayBackCallback;
  12 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
9 13 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
10 14 import org.springframework.http.ResponseEntity;
11 15 import org.springframework.web.context.request.async.DeferredResult;
... ... @@ -17,13 +21,17 @@ public interface IPlayService {
17 21  
18 22 void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid);
19 23  
  24 + void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  25 + ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
  26 + InviteTimeOutCallback timeoutCallback, String uuid);
20 27 PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent, Runnable timeoutCallback);
21 28  
22 29 MediaServerItem getNewMediaServerItem(Device device);
23 30  
24   - void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String toString);
  31 + void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String toString);
25 32  
26   - DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, PlayBackCallback errorCallBack);
  33 + DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
  34 + DeferredResult<ResponseEntity<String>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
27 35  
28 36 void zlmServerOffline(String mediaServerId);
29 37 }
... ...
src/main/java/com/genersoft/iot/vmp/service/bean/InviteTimeOutCallback.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.bean;
  2 +
  3 +public interface InviteTimeOutCallback {
  4 +
  5 + void run(int code, String msg); // code: 0 sip超时, 1 收流超时
  6 +}
... ...
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java
... ... @@ -7,9 +7,9 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
7 7 import javax.sip.RequestEvent;
8 8  
9 9 public class PlayBackResult<T> {
10   - private int code;
11   - private T data;
12   - private MediaServerItem mediaServerItem;
  10 + private int code;
  11 + private T data;
  12 + private MediaServerItem mediaServerItem;
13 13 private JSONObject response;
14 14 private SipSubscribe.EventResult event;
15 15  
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
... ... @@ -512,7 +512,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
512 512 param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
513 513 param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrex));
514 514 param.put("hook.timeoutSec","20");
515   - param.put("general.streamNoneReaderDelayMS","-1".equals(mediaServerItem.getStreamNoneReaderDelayMS())?"3600000":mediaServerItem.getStreamNoneReaderDelayMS() );
  515 + param.put("general.streamNoneReaderDelayMS",mediaServerItem.getStreamNoneReaderDelayMS()==-1?"3600000":mediaServerItem.getStreamNoneReaderDelayMS() );
516 516 // 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。
517 517 // 置0关闭此特性(推流断开会导致立即断开播放器)
518 518 // 此参数不应大于播放器超时时间
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
... ... @@ -16,6 +16,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
16 16 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
17 17 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
18 18 import com.genersoft.iot.vmp.service.IMediaServerService;
  19 +import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;
19 20 import com.genersoft.iot.vmp.service.bean.PlayBackCallback;
20 21 import com.genersoft.iot.vmp.service.bean.PlayBackResult;
21 22 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
... ... @@ -27,6 +28,7 @@ import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
27 28 import com.genersoft.iot.vmp.service.IMediaService;
28 29 import com.genersoft.iot.vmp.service.IPlayService;
29 30 import gov.nist.javax.sip.stack.SIPDialog;
  31 +import jdk.nashorn.internal.ir.RuntimeNode;
30 32 import org.slf4j.Logger;
31 33 import org.slf4j.LoggerFactory;
32 34 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -36,6 +38,9 @@ import org.springframework.stereotype.Service;
36 38 import org.springframework.util.ResourceUtils;
37 39 import org.springframework.web.context.request.async.DeferredResult;
38 40  
  41 +import javax.sip.header.CallIdHeader;
  42 +import javax.sip.header.Header;
  43 +import javax.sip.message.Request;
39 44 import java.io.FileNotFoundException;
40 45 import java.util.*;
41 46  
... ... @@ -79,6 +84,8 @@ public class PlayServiceImpl implements IPlayService {
79 84 private UserSetup userSetup;
80 85  
81 86  
  87 +
  88 +
82 89 @Override
83 90 public PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId,
84 91 ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
... ... @@ -141,67 +148,7 @@ public class PlayServiceImpl implements IPlayService {
141 148 e.printStackTrace();
142 149 }
143 150 });
144   - if (streamInfo == null) {
145   - String streamId = null;
146   - if (mediaServerItem.isRtpEnable()) {
147   - streamId = String.format("%s_%s", device.getDeviceId(), channelId);
148   - }
149   - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId);
150   - // 超时处理
151   - Timer timer = new Timer();
152   - timer.schedule(new TimerTask() {
153   - @Override
154   - public void run() {
155   - logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
156   - if (timeoutCallback != null) {
157   - timeoutCallback.run();
158   - }
159   - WVPResult wvpResult = new WVPResult();
160   - wvpResult.setCode(-1);
161   - SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream());
162   - if (dialog != null) {
163   - wvpResult.setMsg("收流超时,请稍候重试");
164   - // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
165   - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream());
166   - }else {
167   - wvpResult.setMsg("点播超时,请稍候重试");
168   - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
169   - mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream());
170   - streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
171   - }
172   -
173   - msg.setData(wvpResult);
174   -
175   - // 回复之前所有的点播请求
176   - resultHolder.invokeAllResult(msg);
177   - }
178   - }, userSetup.getPlayTimeout());
179   - // 发送点播消息
180   - cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
181   - logger.info("收到订阅消息: " + response.toJSONString());
182   - timer.cancel();
183   - onPublishHandlerForPlay(mediaServerItemInUse, response, deviceId, channelId, uuid);
184   - if (hookEvent != null) {
185   - hookEvent.response(mediaServerItem, response);
186   - }
187   - }, (event) -> {
188   - timer.cancel();
189   - WVPResult wvpResult = new WVPResult();
190   - wvpResult.setCode(-1);
191   - // 点播返回sip错误
192   - mediaServerService.closeRTPServer(playResult.getDevice().getDeviceId(), channelId, ssrcInfo.getStream());
193   - // 释放ssrc
194   - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
195   - streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
196   -
197   - wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg));
198   - msg.setData(wvpResult);
199   - resultHolder.invokeAllResult(msg);
200   - if (errorEvent != null) {
201   - errorEvent.response(event);
202   - }
203   - });
204   - } else {
  151 + if (streamInfo != null) {
205 152 String streamId = streamInfo.getStream();
206 153 if (streamId == null) {
207 154 WVPResult wvpResult = new WVPResult();
... ... @@ -227,67 +174,109 @@ public class PlayServiceImpl implements IPlayService {
227 174 if (hookEvent != null) {
228 175 hookEvent.response(mediaServerItem, JSONObject.parseObject(JSON.toJSONString(streamInfo)));
229 176 }
230   - } else {
231   - // TODO 点播前是否重置状态
  177 + }else {
232 178 redisCatchStorage.stopPlay(streamInfo);
233 179 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
234   - String streamId2 = null;
235   - if (mediaServerItem.isRtpEnable()) {
236   - streamId2 = String.format("%s_%s", device.getDeviceId(), channelId);
237   - }
238   - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId2);
239   - // 超时处理
240   - Timer timer = new Timer();
241   - timer.schedule(new TimerTask() {
242   - @Override
243   - public void run() {
244   - logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
245   - if (timeoutCallback != null) {
246   - timeoutCallback.run();
247   - }
248   - WVPResult wvpResult = new WVPResult();
249   - wvpResult.setCode(-1);
250   - SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream());
251   - if (dialog != null) {
252   - wvpResult.setMsg("收流超时,请稍候重试");
253   - // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
254   - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream());
255   - }else {
256   - wvpResult.setMsg("点播超时,请稍候重试");
257   - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
258   - mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream());
259   - streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
260   - }
261   -
262   - msg.setData(wvpResult);
263   - // 回复之前所有的点播请求
264   - resultHolder.invokeAllResult(msg);
265   - }
266   - }, userSetup.getPlayTimeout());
267   - cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
268   - logger.info("收到订阅消息: " + response.toJSONString());
269   - onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid);
270   - }, (event) -> {
271   - mediaServerService.closeRTPServer(playResult.getDevice().getDeviceId(), channelId, ssrcInfo.getStream());
272   - // 释放ssrc
273   - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
274   - streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
275   - WVPResult wvpResult = new WVPResult();
276   - wvpResult.setCode(-1);
277   - wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg));
278   - msg.setData(wvpResult);
279   - resultHolder.invokeAllResult(msg);
280   - });
  180 + streamInfo = null;
281 181 }
282   - }
283 182  
  183 + }
  184 + if (streamInfo == null) {
  185 + String streamId = null;
  186 + if (mediaServerItem.isRtpEnable()) {
  187 + streamId = String.format("%s_%s", device.getDeviceId(), channelId);
  188 + }
  189 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId);
  190 + play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response)->{
  191 + if (hookEvent != null) {
  192 + hookEvent.response(mediaServerItem, response);
  193 + }
  194 + }, event -> {
  195 + // sip error错误
  196 + WVPResult wvpResult = new WVPResult();
  197 + wvpResult.setCode(-1);
  198 + wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg));
  199 + msg.setData(wvpResult);
  200 + resultHolder.invokeAllResult(msg);
  201 + if (errorEvent != null) {
  202 + errorEvent.response(event);
  203 + }
  204 + }, (code, msgStr)->{
  205 + // invite点播超时
  206 + WVPResult wvpResult = new WVPResult();
  207 + wvpResult.setCode(-1);
  208 + if (code == 0) {
  209 + wvpResult.setMsg("点播超时,请稍候重试");
  210 + }else if (code == 1) {
  211 + wvpResult.setMsg("收流超时,请稍候重试");
  212 + }
  213 + msg.setData(wvpResult);
  214 + // 回复之前所有的点播请求
  215 + resultHolder.invokeAllResult(msg);
  216 + }, uuid);
  217 + }
284 218 return playResult;
285 219 }
286 220  
  221 +
  222 +
  223 + @Override
  224 + public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  225 + ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
  226 + InviteTimeOutCallback timeoutCallback, String uuid) {
  227 +
  228 + String streamId = null;
  229 + if (mediaServerItem.isRtpEnable()) {
  230 + streamId = String.format("%s_%s", device.getDeviceId(), channelId);
  231 + }
  232 + if (ssrcInfo == null) {
  233 + ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId);
  234 + }
  235 +
  236 + // 超时处理
  237 + Timer timer = new Timer();
  238 + SSRCInfo finalSsrcInfo = ssrcInfo;
  239 + timer.schedule(new TimerTask() {
  240 + @Override
  241 + public void run() {
  242 + logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", device.getDeviceId(), channelId));
  243 +
  244 + SIPDialog dialog = streamSession.getDialogByStream(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  245 + if (dialog != null) {
  246 + timeoutCallback.run(1, "收流超时");
  247 + // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
  248 + cmder.streamByeCmd(device.getDeviceId(), channelId, finalSsrcInfo.getStream(), null);
  249 + }else {
  250 + timeoutCallback.run(0, "点播超时");
  251 + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
  252 + mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  253 + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  254 + }
  255 + }
  256 + }, userSetup.getPlayTimeout());
  257 +
  258 + cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
  259 + logger.info("收到订阅消息: " + response.toJSONString());
  260 + timer.cancel();
  261 + // hook响应
  262 + onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId, uuid);
  263 + hookEvent.response(mediaServerItemInuse, response);
  264 + }, (event) -> {
  265 + timer.cancel();
  266 + mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  267 + // 释放ssrc
  268 + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
  269 + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  270 + errorEvent.response(event);
  271 + });
  272 + }
  273 +
287 274 @Override
288 275 public void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) {
289 276 RequestMessage msg = new RequestMessage();
290   - msg.setId(uuid);
  277 + if (uuid != null) {
  278 + msg.setId(uuid);
  279 + }
291 280 msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId);
292 281 StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
293 282 if (streamInfo != null) {
... ... @@ -297,7 +286,6 @@ public class PlayServiceImpl implements IPlayService {
297 286 storager.startPlay(deviceId, channelId, streamInfo.getStream());
298 287 }
299 288 redisCatchStorage.startPlay(streamInfo);
300   - msg.setData(JSON.toJSONString(streamInfo));
301 289  
302 290 WVPResult wvpResult = new WVPResult();
303 291 wvpResult.setCode(0);
... ... @@ -329,9 +317,24 @@ public class PlayServiceImpl implements IPlayService {
329 317 return mediaServerItem;
330 318 }
331 319  
  320 + @Override
  321 + public DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime,
  322 + String endTime,InviteStreamCallback inviteStreamCallback,
  323 + PlayBackCallback callback) {
  324 + Device device = storager.queryVideoDevice(deviceId);
  325 + if (device == null) return null;
  326 + MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
  327 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true);
  328 +
  329 + return playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback);
  330 + }
332 331  
333 332 @Override
334   - public DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, PlayBackCallback callback) {
  333 + public DeferredResult<ResponseEntity<String>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
  334 + String deviceId, String channelId, String startTime,
  335 + String endTime, InviteStreamCallback infoCallBack,
  336 + PlayBackCallback playBackCallback) {
  337 + if (mediaServerItem == null || ssrcInfo == null) return null;
335 338 String uuid = UUID.randomUUID().toString();
336 339 String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
337 340 DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(30000L);
... ... @@ -341,8 +344,6 @@ public class PlayServiceImpl implements IPlayService {
341 344 return result;
342 345 }
343 346  
344   - MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
345   - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true);
346 347 resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId, uuid, result);
347 348 RequestMessage msg = new RequestMessage();
348 349 msg.setId(uuid);
... ... @@ -356,63 +357,62 @@ public class PlayServiceImpl implements IPlayService {
356 357 logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
357 358 playBackResult.setCode(-1);
358 359 playBackResult.setData(msg);
359   - callback.call(playBackResult);
  360 + playBackCallback.call(playBackResult);
360 361 SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream());
361 362 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
362 363 if (dialog != null) {
363 364 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
364   - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream());
  365 + cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null);
365 366 }else {
366   - mediaServerService.releaseSsrc(newMediaServerItem.getId(), ssrcInfo.getSsrc());
  367 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
367 368 mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream());
368 369 streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
369 370 }
370   - cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream());
  371 + cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null);
371 372 // 回复之前所有的点播请求
372   - callback.call(playBackResult);
  373 + playBackCallback.call(playBackResult);
373 374 }
374 375 }, userSetup.getPlayTimeout());
375   - cmder.playbackStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, (MediaServerItem mediaServerItem, JSONObject response) -> {
376   - logger.info("收到订阅消息: " + response.toJSONString());
377   - timer.cancel();
378   - StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
379   - if (streamInfo == null) {
380   - logger.warn("设备回放API调用失败!");
381   - msg.setData("设备回放API调用失败!");
382   - playBackResult.setCode(-1);
383   - playBackResult.setData(msg);
384   - callback.call(playBackResult);
385   - return;
386   - }
387   - redisCatchStorage.startPlayback(streamInfo);
388   - msg.setData(JSON.toJSONString(streamInfo));
389   - playBackResult.setCode(0);
390   - playBackResult.setData(msg);
391   - playBackResult.setMediaServerItem(mediaServerItem);
392   - playBackResult.setResponse(response);
393   - callback.call(playBackResult);
394   - }, event -> {
395   - timer.cancel();
396   - msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
397   - playBackResult.setCode(-1);
398   - playBackResult.setData(msg);
399   - playBackResult.setEvent(event);
400   - callback.call(playBackResult);
401   - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
402   - });
  376 + cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack,
  377 + (InviteStreamInfo inviteStreamInfo) -> {
  378 + logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString());
  379 + timer.cancel();
  380 + StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
  381 + if (streamInfo == null) {
  382 + logger.warn("设备回放API调用失败!");
  383 + msg.setData("设备回放API调用失败!");
  384 + playBackResult.setCode(-1);
  385 + playBackResult.setData(msg);
  386 + playBackCallback.call(playBackResult);
  387 + return;
  388 + }
  389 + redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId());
  390 + msg.setData(JSON.toJSONString(streamInfo));
  391 + playBackResult.setCode(0);
  392 + playBackResult.setData(msg);
  393 + playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
  394 + playBackResult.setResponse(inviteStreamInfo.getResponse());
  395 + playBackCallback.call(playBackResult);
  396 + }, event -> {
  397 + timer.cancel();
  398 + msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
  399 + playBackResult.setCode(-1);
  400 + playBackResult.setData(msg);
  401 + playBackResult.setEvent(event);
  402 + playBackCallback.call(playBackResult);
  403 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  404 + });
403 405 return result;
404 406 }
405 407  
406   -
407   -
408 408 @Override
409   - public void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) {
  409 + public void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String uuid) {
410 410 RequestMessage msg = new RequestMessage();
411 411 msg.setKey(DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId);
412 412 msg.setId(uuid);
413   - StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
  413 + StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
414 414 if (streamInfo != null) {
415   - redisCatchStorage.startDownload(streamInfo);
  415 + redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());
416 416 msg.setData(JSON.toJSONString(streamInfo));
417 417 resultHolder.invokeResult(msg);
418 418 } else {
... ... @@ -449,7 +449,8 @@ public class PlayServiceImpl implements IPlayService {
449 449 if (allSsrc.size() > 0) {
450 450 for (SsrcTransaction ssrcTransaction : allSsrc) {
451 451 if(ssrcTransaction.getMediaServerId().equals(mediaServerId)) {
452   - cmder.streamByeCmd(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
  452 + cmder.streamByeCmd(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(),
  453 + ssrcTransaction.getStream(), null);
453 454 }
454 455 }
455 456 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
... ... @@ -47,17 +47,15 @@ public interface IRedisCatchStorage {
47 47  
48 48 StreamInfo queryPlayByStreamId(String steamId);
49 49  
50   - StreamInfo queryPlaybackByStreamId(String steamId);
51   -
52 50 StreamInfo queryPlayByDevice(String deviceId, String channelId);
53 51  
54 52 Map<String, StreamInfo> queryPlayByDeviceId(String deviceId);
55 53  
56   - boolean startPlayback(StreamInfo stream);
  54 + boolean startPlayback(StreamInfo stream, String callId);
57 55  
58   - boolean stopPlayback(StreamInfo streamInfo);
  56 + boolean stopPlayback(String deviceId, String channelId, String stream, String callId);
59 57  
60   - StreamInfo queryPlaybackByDevice(String deviceId, String code);
  58 + StreamInfo queryPlayback(String deviceId, String channelID, String stream, String callId);
61 59  
62 60 void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch);
63 61  
... ... @@ -167,9 +165,9 @@ public interface IRedisCatchStorage {
167 165 * 开始下载录像时存入
168 166 * @param streamInfo
169 167 */
170   - boolean startDownload(StreamInfo streamInfo);
  168 + boolean startDownload(StreamInfo streamInfo, String callId);
171 169  
172   - StreamInfo queryDownloadByStreamId(String streamId);
  170 + StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId);
173 171  
174 172 /**
175 173 * 查找第三方系统留下的国标预设值
... ... @@ -204,18 +202,8 @@ public interface IRedisCatchStorage {
204 202  
205 203 void resetAllSN();
206 204  
207   - void updateSubscribe(String key, SubscribeInfo subscribeInfo);
208   -
209   - SubscribeInfo getSubscribe(String key);
210   -
211   - void delSubscribe(String key);
212   -
213 205 MediaItem getStreamInfo(String app, String streamId, String mediaServerId);
214 206  
215   - List<SubscribeInfo> getAllSubscribe();
216   -
217   - List<String> getAllSubscribePlatform();
218   -
219 207 void addCpuInfo(double cpuInfo);
220 208  
221 209 void addMemInfo(double memInfo);
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
... ... @@ -231,7 +231,6 @@ public interface DeviceChannelMapper {
231 231 " name as title,\n" +
232 232 " channelId as \"value\",\n" +
233 233 " channelId as \"key\",\n" +
234   - " channelId,\n" +
235 234 " longitude,\n" +
236 235 " latitude\n" +
237 236 " from device_channel\n" +
... ... @@ -248,4 +247,13 @@ public interface DeviceChannelMapper {
248 247 "<foreach collection='channels' item='item' open='(' separator=',' close=')' > #{item.channelId}</foreach>" +
249 248 " </script>"})
250 249 int cleanChannelsNotInList(String deviceId, List<DeviceChannel> channels);
  250 +
  251 + @Update(" update device_channel" +
  252 + " set subCount = (select *" +
  253 + " from (select count(0)" +
  254 + " from device_channel" +
  255 + " where deviceId = #{deviceId} and parentId = #{channelId}) as temp)" +
  256 + " where deviceId = #{deviceId} " +
  257 + " and channelId = #{channelId}")
  258 + int updateChannelSubCount(String deviceId, String channelId);
251 259 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
... ... @@ -55,7 +55,7 @@ public interface PlatformChannelMapper {
55 55 int cleanChannelForGB(String platformId);
56 56  
57 57 @Select("SELECT dc.* FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE dc.channelId='${channelId}' and pgc.platformId='${platformId}'")
58   - DeviceChannel queryChannelInParentPlatform(String platformId, String channelId);
  58 + List<DeviceChannel> queryChannelInParentPlatform(String platformId, String channelId);
59 59  
60 60 @Select(" select dc.channelId as id, dc.name as name, pgc.platformId as platformId, pgc.catalogId as parentId, 0 as childrenCount, 1 as type " +
61 61 " from device_channel dc left join platform_gb_channel pgc on dc.id = pgc.deviceChannelId " +
... ... @@ -67,7 +67,7 @@ public interface PlatformChannelMapper {
67 67 " left join device_channel dc on dc.id = pgc.deviceChannelId\n" +
68 68 " left join device d on dc.deviceId = d.deviceId\n" +
69 69 "where dc.channelId = #{channelId} and pgc.platformId=#{platformId}")
70   - Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId);
  70 + List<Device> queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId);
71 71  
72 72 @Delete("<script> "+
73 73 "DELETE FROM platform_gb_channel WHERE catalogId=#{id}" +
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
... ... @@ -134,13 +134,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
134 134 }
135 135  
136 136 @Override
137   - public StreamInfo queryPlaybackByStreamId(String streamId) {
138   - List<Object> playLeys = redis.scan(String.format("%S_%s_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, userSetup.getServerId(), streamId));
139   - if (playLeys == null || playLeys.size() == 0) return null;
140   - return (StreamInfo)redis.get(playLeys.get(0).toString());
141   - }
142   -
143   - @Override
144 137 public StreamInfo queryPlayByDevice(String deviceId, String channelId) {
145 138 List<Object> playLeys = redis.scan(String.format("%S_%s_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
146 139 userSetup.getServerId(),
... ... @@ -166,49 +159,67 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
166 159  
167 160  
168 161 @Override
169   - public boolean startPlayback(StreamInfo stream) {
170   - return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
171   - userSetup.getServerId(), stream.getStream(), stream.getDeviceID(), stream.getChannelId()), stream);
  162 + public boolean startPlayback(StreamInfo stream, String callId) {
  163 + return redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
  164 + userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream);
172 165 }
173 166  
174 167 @Override
175   - public boolean startDownload(StreamInfo streamInfo) {
176   - return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, userSetup.getServerId(),
177   - streamInfo.getStream(), streamInfo.getDeviceID(), streamInfo.getChannelId()), streamInfo);
  168 + public boolean startDownload(StreamInfo stream, String callId) {
  169 + return redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
  170 + userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream);
178 171 }
179 172  
180 173 @Override
181   - public boolean stopPlayback(StreamInfo streamInfo) {
182   - if (streamInfo == null) return false;
183   - DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(streamInfo.getDeviceID(), streamInfo.getChannelId());
  174 + public boolean stopPlayback(String deviceId, String channelId, String stream, String callId) {
  175 + DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);
184 176 if (deviceChannel != null) {
185 177 deviceChannel.setStreamId(null);
186   - deviceChannel.setDeviceId(streamInfo.getDeviceID());
  178 + deviceChannel.setDeviceId(deviceId);
187 179 deviceChannelMapper.update(deviceChannel);
188 180 }
189   - return redis.del(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
  181 + if (deviceId == null) deviceId = "*";
  182 + if (channelId == null) channelId = "*";
  183 + if (stream == null) stream = "*";
  184 + if (callId == null) callId = "*";
  185 + String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
190 186 userSetup.getServerId(),
191   - streamInfo.getStream(),
192   - streamInfo.getDeviceID(),
193   - streamInfo.getChannelId()));
  187 + deviceId,
  188 + channelId,
  189 + stream,
  190 + callId
  191 + );
  192 + List<Object> scan = redis.scan(key);
  193 + if (scan.size() > 0) {
  194 + for (Object keyObj : scan) {
  195 + redis.del((String) keyObj);
  196 + }
  197 + }
  198 + return true;
194 199 }
195 200  
196 201 @Override
197   - public StreamInfo queryPlaybackByDevice(String deviceId, String code) {
198   - // String format = String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
199   - // deviceId,
200   - // code);
201   - List<Object> playLeys = redis.scan(String.format("%S_%s_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
  202 + public StreamInfo queryPlayback(String deviceId, String channelId, String stream, String callId) {
  203 + if (stream == null && callId == null) {
  204 + return null;
  205 + }
  206 + if (deviceId == null) deviceId = "*";
  207 + if (channelId == null) channelId = "*";
  208 + if (stream == null) stream = "*";
  209 + if (callId == null) callId = "*";
  210 + String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
202 211 userSetup.getServerId(),
203 212 deviceId,
204   - code));
205   - if (playLeys == null || playLeys.size() == 0) {
206   - playLeys = redis.scan(String.format("%S_%s_*_*_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
207   - userSetup.getServerId(),
208   - deviceId));
  213 + channelId,
  214 + stream,
  215 + callId
  216 + );
  217 + List<Object> streamInfoScan = redis.scan(key);
  218 + if (streamInfoScan.size() > 0) {
  219 + return (StreamInfo) redis.get((String) streamInfoScan.get(0));
  220 + }else {
  221 + return null;
209 222 }
210   - if (playLeys == null || playLeys.size() == 0) return null;
211   - return (StreamInfo)redis.get(playLeys.get(0).toString());
212 223 }
213 224  
214 225 @Override
... ... @@ -361,7 +372,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
361 372 }
362 373 }
363 374  
364   - List<Object> playBackers = redis.scan(String.format("%S_%s_*_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX,
  375 + List<Object> playBackers = redis.scan(String.format("%S_%s_%s_*_*_*", VideoManagerConstants.PLAY_BLACK_PREFIX,
365 376 userSetup.getServerId(),
366 377 deviceId));
367 378 if (playBackers.size() > 0) {
... ... @@ -426,10 +437,27 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
426 437 }
427 438  
428 439 @Override
429   - public StreamInfo queryDownloadByStreamId(String streamId) {
430   - List<Object> playLeys = redis.scan(String.format("%S_%s_%s_*", VideoManagerConstants.DOWNLOAD_PREFIX, userSetup.getServerId(), streamId));
431   - if (playLeys == null || playLeys.size() == 0) return null;
432   - return (StreamInfo)redis.get(playLeys.get(0).toString());
  440 + public StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId) {
  441 + if (stream == null && callId == null) {
  442 + return null;
  443 + }
  444 + if (deviceId == null) deviceId = "*";
  445 + if (channelId == null) channelId = "*";
  446 + if (stream == null) stream = "*";
  447 + if (callId == null) callId = "*";
  448 + String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
  449 + userSetup.getServerId(),
  450 + deviceId,
  451 + channelId,
  452 + stream,
  453 + callId
  454 + );
  455 + List<Object> streamInfoScan = redis.scan(key);
  456 + if (streamInfoScan.size() > 0) {
  457 + return (StreamInfo) redis.get((String) streamInfoScan.get(0));
  458 + }else {
  459 + return null;
  460 + }
433 461 }
434 462  
435 463 @Override
... ... @@ -491,21 +519,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
491 519 }
492 520  
493 521 @Override
494   - public void updateSubscribe(String key, SubscribeInfo subscribeInfo) {
495   - redis.set(key, subscribeInfo, subscribeInfo.getExpires());
496   - }
497   -
498   - @Override
499   - public SubscribeInfo getSubscribe(String key) {
500   - return (SubscribeInfo)redis.get(key);
501   - }
502   -
503   - @Override
504   - public void delSubscribe(String key) {
505   - redis.del(key);
506   - }
507   -
508   - @Override
509 522 public List<GPSMsgInfo> getAllGpsMsgInfo() {
510 523 String scanKey = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetup.getServerId() + "_*";
511 524 List<GPSMsgInfo> result = new ArrayList<>();
... ... @@ -536,32 +549,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
536 549 }
537 550  
538 551 @Override
539   - public List<SubscribeInfo> getAllSubscribe() {
540   - String scanKey = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_*";
541   - List<SubscribeInfo> result = new ArrayList<>();
542   - List<Object> keys = redis.scan(scanKey);
543   - for (int i = 0; i < keys.size(); i++) {
544   - String key = (String) keys.get(i);
545   - SubscribeInfo subscribeInfo = (SubscribeInfo) redis.get(key);
546   - result.add(subscribeInfo);
547   - }
548   - return result;
549   - }
550   -
551   - @Override
552   - public List<String> getAllSubscribePlatform() {
553   - String scanKey = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_*";
554   - List<String> result = new ArrayList<>();
555   - List<Object> keys = redis.scan(scanKey);
556   - for (int i = 0; i < keys.size(); i++) {
557   - String key = (String) keys.get(i);
558   - String platformId = key.substring(scanKey.length() - 1);
559   - result.add(platformId);
560   - }
561   - return result;
562   - }
563   -
564   - @Override
565 552 public void addCpuInfo(double cpuInfo) {
566 553 String key = VideoManagerConstants.SYSTEM_INFO_CPU_PREFIX + userSetup.getServerId();
567 554 SystemInfoDto<Double> systemInfoDto = new SystemInfoDto<>();
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
... ... @@ -42,7 +42,7 @@ import java.util.*;
42 42 @Component
43 43 public class VideoManagerStoragerImpl implements IVideoManagerStorager {
44 44  
45   - private Logger logger = LoggerFactory.getLogger(VideoManagerStoragerImpl.class);
  45 + private final Logger logger = LoggerFactory.getLogger(VideoManagerStoragerImpl.class);
46 46  
47 47 @Autowired
48 48 EventPublisher eventPublisher;
... ... @@ -171,6 +171,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
171 171 }else {
172 172 deviceChannelMapper.update(channel);
173 173 }
  174 + deviceChannelMapper.updateChannelSubCount(deviceId,channel.getParentId());
174 175 }
175 176  
176 177 @Override
... ... @@ -542,7 +543,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
542 543 if (parentPlatformCatch == null) { // serverGBId 已变化
543 544 ParentPlatform parentPlatById = platformMapper.getParentPlatById(parentPlatform.getId());
544 545 // 使用旧的查出缓存ID
545   - parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatById.getServerGBId());
  546 + parentPlatformCatch = new ParentPlatformCatch();
546 547 parentPlatformCatch.setId(parentPlatform.getServerGBId());
547 548 redisCatchStorage.delPlatformCatchInfo(parentPlatById.getServerGBId());
548 549 }
... ... @@ -662,8 +663,16 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
662 663  
663 664 @Override
664 665 public DeviceChannel queryChannelInParentPlatform(String platformId, String channelId) {
665   - DeviceChannel channel = platformChannelMapper.queryChannelInParentPlatform(platformId, channelId);
666   - return channel;
  666 + List<DeviceChannel> channels = platformChannelMapper.queryChannelInParentPlatform(platformId, channelId);
  667 + if (channels.size() > 1) {
  668 + // 出现长度大于0的时候肯定是国标通道的ID重复了
  669 + logger.warn("国标ID存在重复:{}", channelId);
  670 + }
  671 + if (channels.size() == 0) {
  672 + return null;
  673 + }else {
  674 + return channels.get(0);
  675 + }
667 676 }
668 677  
669 678 @Override
... ... @@ -680,8 +689,18 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
680 689  
681 690 @Override
682 691 public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) {
683   - Device device = platformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId);
684   - return device;
  692 + List<Device> devices = platformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId);
  693 + if (devices.size() > 1) {
  694 + // 出现长度大于0的时候肯定是国标通道的ID重复了
  695 + logger.warn("国标ID存在重复:{}", channelId);
  696 + }
  697 + if (devices.size() == 0) {
  698 + return null;
  699 + }else {
  700 + return devices.get(0);
  701 + }
  702 +
  703 +
685 704 }
686 705  
687 706 /**
... ... @@ -1083,6 +1102,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
1083 1102  
1084 1103 @Override
1085 1104 public List<ParentPlatform> queryPlatFormListForStreamWithGBId(String app, String stream, List<String> platforms) {
  1105 + if (platforms == null || platforms.size() == 0) {
  1106 + return new ArrayList<>();
  1107 + }
1086 1108 return platformGbStreamMapper.queryPlatFormListForGBWithGBId(app, stream, platforms);
1087 1109 }
1088 1110  
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
... ... @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.conf.DynamicTask;
7 7 import com.genersoft.iot.vmp.conf.UserSetup;
8 8 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
9 9 import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
  10 +import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
10 11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
11 12 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
12 13 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
... ... @@ -50,6 +51,9 @@ public class PlatformController {
50 51 private IRedisCatchStorage redisCatchStorage;
51 52  
52 53 @Autowired
  54 + private SubscribeHolder subscribeHolder;
  55 +
  56 + @Autowired
53 57 private ISIPCommanderForPlatform commanderForPlatform;
54 58  
55 59 @Autowired
... ... @@ -110,10 +114,14 @@ public class PlatformController {
110 114 })
111 115 public PageInfo<ParentPlatform> platforms(@PathVariable int page, @PathVariable int count) {
112 116  
113   -// if (logger.isDebugEnabled()) {
114   -// logger.debug("查询所有上级设备API调用");
115   -// }
116   - return storager.queryParentPlatformList(page, count);
  117 + PageInfo<ParentPlatform> parentPlatformPageInfo = storager.queryParentPlatformList(page, count);
  118 + if (parentPlatformPageInfo.getList().size() > 0) {
  119 + for (ParentPlatform platform : parentPlatformPageInfo.getList()) {
  120 + platform.setGpsSubscribe(subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId()) != null);
  121 + platform.setCatalogSubscribe(subscribeHolder.getCatalogSubscribe(platform.getServerGBId()) != null);
  122 + }
  123 + }
  124 + return parentPlatformPageInfo;
117 125 }
118 126  
119 127 /**
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
... ... @@ -120,7 +120,7 @@ public class PlayController {
120 120 storager.stopPlay(deviceId, channelId);
121 121 return result;
122 122 }
123   - cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream(), (event) -> {
  123 + cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream(), null, (event) -> {
124 124 redisCatchStorage.stopPlay(streamInfo);
125 125 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
126 126 RequestMessage msg = new RequestMessage();
... ... @@ -174,7 +174,7 @@ public class PlayController {
174 174 public ResponseEntity<String> playConvert(@PathVariable String streamId) {
175 175 StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
176 176 if (streamInfo == null) {
177   - streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId);
  177 + streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
178 178 }
179 179 if (streamInfo == null) {
180 180 logger.warn("视频转码API调用失败!, 视频流已经停止!");
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/DownloadController.java
1 1 package com.genersoft.iot.vmp.vmanager.gb28181.playback;
2 2  
3 3 import com.genersoft.iot.vmp.common.StreamInfo;
  4 +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo;
4 5 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
5 6 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
6 7 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
... ... @@ -93,11 +94,6 @@ public class DownloadController {
93 94 }
94 95 resultHolder.put(key, uuid, result);
95 96 Device device = storager.queryVideoDevice(deviceId);
96   - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId);
97   - if (streamInfo != null) {
98   - // 停止之前的下载
99   - cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream());
100   - }
101 97  
102 98 MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
103 99 if (newMediaServerItem == null) {
... ... @@ -112,9 +108,9 @@ public class DownloadController {
112 108  
113 109 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true);
114 110  
115   - cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (MediaServerItem mediaServerItem, JSONObject response) -> {
116   - logger.info("收到订阅消息: " + response.toJSONString());
117   - playService.onPublishHandlerForDownload(mediaServerItem, response, deviceId, channelId, uuid);
  111 + cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (InviteStreamInfo inviteStreamInfo) -> {
  112 + logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString());
  113 + playService.onPublishHandlerForDownload(inviteStreamInfo, deviceId, channelId, uuid);
118 114 }, event -> {
119 115 RequestMessage msg = new RequestMessage();
120 116 msg.setId(uuid);
... ... @@ -135,7 +131,7 @@ public class DownloadController {
135 131 @GetMapping("/stop/{deviceId}/{channelId}/{stream}")
136 132 public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) {
137 133  
138   - cmder.streamByeCmd(deviceId, channelId, stream);
  134 + cmder.streamByeCmd(deviceId, channelId, stream, null);
139 135  
140 136 if (logger.isDebugEnabled()) {
141 137 logger.debug(String.format("设备历史媒体下载停止 API调用,deviceId/channelId:%s_%s", deviceId, channelId));
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
... ... @@ -77,7 +77,7 @@ public class PlaybackController {
77 77 logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId));
78 78 }
79 79  
80   - DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, wvpResult->{
  80 + DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, null, wvpResult->{
81 81 resultHolder.invokeResult(wvpResult.getData());
82 82 });
83 83  
... ... @@ -96,7 +96,7 @@ public class PlaybackController {
96 96 @PathVariable String channelId,
97 97 @PathVariable String stream) {
98 98  
99   - cmder.streamByeCmd(deviceId, channelId, stream);
  99 + cmder.streamByeCmd(deviceId, channelId, stream, null);
100 100  
101 101 if (logger.isDebugEnabled()) {
102 102 logger.debug(String.format("设备录像回放停止 API调用,deviceId/channelId:%s/%s", deviceId, channelId));
... ... @@ -124,7 +124,7 @@ public class PlaybackController {
124 124 public ResponseEntity<String> playPause(@PathVariable String streamId) {
125 125 logger.info("playPause: "+streamId);
126 126 JSONObject json = new JSONObject();
127   - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId);
  127 + StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
128 128 if (null == streamInfo) {
129 129 json.put("msg", "streamId不存在");
130 130 logger.warn("streamId不存在!");
... ... @@ -144,7 +144,7 @@ public class PlaybackController {
144 144 public ResponseEntity<String> playResume(@PathVariable String streamId) {
145 145 logger.info("playResume: "+streamId);
146 146 JSONObject json = new JSONObject();
147   - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId);
  147 + StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
148 148 if (null == streamInfo) {
149 149 json.put("msg", "streamId不存在");
150 150 logger.warn("streamId不存在!");
... ... @@ -165,7 +165,7 @@ public class PlaybackController {
165 165 public ResponseEntity<String> playSeek(@PathVariable String streamId, @PathVariable long seekTime) {
166 166 logger.info("playSeek: "+streamId+", "+seekTime);
167 167 JSONObject json = new JSONObject();
168   - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId);
  168 + StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
169 169 if (null == streamInfo) {
170 170 json.put("msg", "streamId不存在");
171 171 logger.warn("streamId不存在!");
... ... @@ -186,7 +186,7 @@ public class PlaybackController {
186 186 public ResponseEntity<String> playSpeed(@PathVariable String streamId, @PathVariable Double speed) {
187 187 logger.info("playSpeed: "+streamId+", "+speed);
188 188 JSONObject json = new JSONObject();
189   - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId);
  189 + StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
190 190 if (null == streamInfo) {
191 191 json.put("msg", "streamId不存在");
192 192 logger.warn("streamId不存在!");
... ...
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
... ... @@ -177,7 +177,7 @@ public class ApiStreamController {
177 177 result.put("error","未找到流信息");
178 178 return result;
179 179 }
180   - cmder.streamByeCmd(serial, code, streamInfo.getStream());
  180 + cmder.streamByeCmd(serial, code, streamInfo.getStream(), null);
181 181 redisCatchStorage.stopPlay(streamInfo);
182 182 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
183 183 return null;
... ...
web_src/src/components/ParentPlatformList.vue
... ... @@ -13,7 +13,7 @@
13 13 </div>
14 14 <!--设备列表-->
15 15 <el-table :data="platformList" border style="width: 100%" :height="winHeight">
16   - <el-table-column prop="name" label="名称" width="240" align="center"></el-table-column>
  16 + <el-table-column prop="name" label="名称" align="center"></el-table-column>
17 17 <el-table-column prop="serverGBId" label="平台编号" width="180" align="center"></el-table-column>
18 18 <el-table-column label="是否启用" width="120" align="center">
19 19 <template slot-scope="scope">
... ... @@ -38,9 +38,19 @@
38 38 </div>
39 39 </template>
40 40 </el-table-column>
41   - <el-table-column prop="deviceGBId" label="设备国标编号" width="240" align="center"></el-table-column>
  41 + <el-table-column prop="deviceGBId" label="设备国标编号" width="200" align="center"></el-table-column>
42 42 <el-table-column prop="transport" label="信令传输模式" width="120" align="center"></el-table-column>
43   - <el-table-column prop="channelCount" label="通道数" align="center"></el-table-column>
  43 + <el-table-column prop="channelCount" label="通道数" width="120" align="center"></el-table-column>
  44 + <el-table-column label="订阅信息" width="240" align="center" fixed="right">
  45 + <template slot-scope="scope">
  46 + <i v-if="scope.row.alarmSubscribe" style="font-size: 1.5rem;" title="报警订阅" class="subscribe-on iconfont icon-gbaojings" ></i>
  47 + <i v-if="!scope.row.alarmSubscribe" style="font-size: 1.5rem;" title="报警订阅" class="subscribe-off iconfont icon-gbaojings" ></i>
  48 + <i v-if="scope.row.catalogSubscribe" title="目录订阅" class="subscribe-on iconfont icon-gjichus" ></i>
  49 + <i v-if="!scope.row.catalogSubscribe" title="目录订阅" class="subscribe-off iconfont icon-gjichus" ></i>
  50 + <i v-if="scope.row.gpsSubscribe" title="位置订阅" class="subscribe-on iconfont icon-gxunjians" ></i>
  51 + <i v-if="!scope.row.gpsSubscribe" title="位置订阅" class="subscribe-off iconfont icon-gxunjians" ></i>
  52 + </template>
  53 + </el-table-column>
44 54  
45 55 <el-table-column label="操作" width="300" align="center" fixed="right">
46 56 <template slot-scope="scope">
... ... @@ -169,3 +179,13 @@ export default {
169 179 }
170 180 };
171 181 </script>
  182 +<style>
  183 +.subscribe-on{
  184 + color: #409EFF;
  185 + font-size: 1.3rem;
  186 +}
  187 +.subscribe-off{
  188 + color: #afafb3;
  189 + font-size: 1.3rem;
  190 +}
  191 +</style>
... ...
web_src/src/components/dialog/StreamProxyEdit.vue
... ... @@ -193,6 +193,7 @@ export default {
193 193 this.mediaServer.getOnlineMediaServerList((data)=>{
194 194 this.mediaServerList = data.data;
195 195 this.proxyParam.mediaServerId = this.mediaServerList[0].id
  196 + this.mediaServerIdChange()
196 197 })
197 198 },
198 199 mediaServerIdChange:function (){
... ... @@ -206,6 +207,7 @@ export default {
206 207 }
207 208 }).then(function (res) {
208 209 that.ffmpegCmdList = res.data.data;
  210 + that.proxyParam.ffmpeg_cmd_key = Object.keys(res.data.data)[0];
209 211 }).catch(function (error) {
210 212 console.log(error);
211 213 });
... ...
web_src/src/components/dialog/chooseChannelForGb.vue
1 1 <template>
2 2 <div id="chooseChannelForGb" >
3 3 <div style="font-size: 17px; color: #606060; white-space: nowrap; line-height: 30px; font-family: monospace;">
4   - <span v-if="catalogId == null">{{catalogName}}的直播流</span>
5   - <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的直播流</span>
  4 + <span v-if="catalogId == null">{{catalogName}}的国标通道</span>
  5 + <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的国标通道</span>
6 6 </div>
7 7 <div style="background-color: #FFFFFF; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;">
8 8 搜索: <el-input @input="search" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字" prefix-icon="el-icon-search" v-model="searchSrt" clearable> </el-input>
... ...
web_src/src/components/dialog/chooseChannelForStream.vue
1 1 <template>
2 2 <div id="chooseChannelFoStream" >
3 3 <div style="font-size: 17px; color: #606060; white-space: nowrap; line-height: 30px; font-family: monospace;">
4   - <span v-if="catalogId == null">{{catalogName}}的直播流</span>
5   - <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的直播流</span>
  4 + <span v-if="catalogId == null">{{catalogName}}的直播通道</span>
  5 + <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的直播通道</span>
6 6 </div>
7 7 <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;">
8 8  
... ...
web_src/static/css/iconfont.css
1 1 @font-face {
2 2 font-family: "iconfont"; /* Project id 1291092 */
3   - src: url('iconfont.woff2?t=1644809302709') format('woff2'),
4   - url('iconfont.woff?t=1644809302709') format('woff'),
5   - url('iconfont.ttf?t=1644809302709') format('truetype');
  3 + src: url('iconfont.woff2?t=1647245982270') format('woff2'),
  4 + url('iconfont.woff?t=1647245982270') format('woff'),
  5 + url('iconfont.ttf?t=1647245982270') format('truetype');
6 6 }
7 7  
8 8 .iconfont {
... ... @@ -13,6 +13,22 @@
13 13 -moz-osx-font-smoothing: grayscale;
14 14 }
15 15  
  16 +.icon-xitongxinxi:before {
  17 + content: "\e7d6";
  18 +}
  19 +
  20 +.icon-gbaojings:before {
  21 + content: "\e7d7";
  22 +}
  23 +
  24 +.icon-gjichus:before {
  25 + content: "\e7d8";
  26 +}
  27 +
  28 +.icon-gxunjians:before {
  29 + content: "\e7d9";
  30 +}
  31 +
16 32 .icon-ziyuan:before {
17 33 content: "\e7d5";
18 34 }
... ...
web_src/static/css/iconfont.woff2
No preview for this file type