Commit 14174ff40022a1f7662759d478d06b7b350ccd98

Authored by 648540858
2 parents 1dcdbc37 2eb1ca2d

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

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
Showing 38 changed files with 312 additions and 234 deletions
sql/mysql.sql
... ... @@ -415,6 +415,7 @@ DROP TABLE IF EXISTS `stream_proxy`;
415 415 CREATE TABLE `stream_proxy` (
416 416 `id` int NOT NULL AUTO_INCREMENT,
417 417 `type` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
  418 + `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL,
418 419 `app` varchar(255) COLLATE utf8mb4_general_ci NOT NULL,
419 420 `stream` varchar(255) COLLATE utf8mb4_general_ci NOT NULL,
420 421 `url` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
... ...
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
... ... @@ -5,7 +5,7 @@ import com.alibaba.fastjson.JSONArray;
5 5 public class StreamInfo {
6 6  
7 7 private String app;
8   - private String streamId;
  8 + private String stream;
9 9 private String deviceID;
10 10 private String channelId;
11 11 private String flv;
... ... @@ -153,12 +153,12 @@ public class StreamInfo {
153 153 this.ws_ts = ws_ts;
154 154 }
155 155  
156   - public String getStreamId() {
157   - return streamId;
  156 + public String getStream() {
  157 + return stream;
158 158 }
159 159  
160   - public void setStreamId(String streamId) {
161   - this.streamId = streamId;
  160 + public void setStream(String stream) {
  161 + this.stream = stream;
162 162 }
163 163  
164 164 public String getRtc() {
... ...
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
... ... @@ -29,6 +29,7 @@ public class VideoManagerConstants {
29 29 // 此处多了一个_,暂不修改
30 30 public static final String PLAYER_PREFIX = "VMP_PLAYER_";
31 31 public static final String PLAY_BLACK_PREFIX = "VMP_PLAYBACK_";
  32 + public static final String PLAY_INFO_PREFIX = "VMP_PLAY_INFO_";
32 33  
33 34 public static final String DOWNLOAD_PREFIX = "VMP_DOWNLOAD_";
34 35  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java
... ... @@ -4,11 +4,12 @@ public class SsrcTransaction {
4 4  
5 5 private String deviceId;
6 6 private String channelId;
7   - private String ssrc;
8   - private String streamId;
  7 + private String callId;
  8 + private String stream;
9 9 private byte[] transaction;
10 10 private byte[] dialog;
11 11 private String mediaServerId;
  12 + private String ssrc;
12 13  
13 14 public String getDeviceId() {
14 15 return deviceId;
... ... @@ -26,20 +27,20 @@ public class SsrcTransaction {
26 27 this.channelId = channelId;
27 28 }
28 29  
29   - public String getSsrc() {
30   - return ssrc;
  30 + public String getCallId() {
  31 + return callId;
31 32 }
32 33  
33   - public void setSsrc(String ssrc) {
34   - this.ssrc = ssrc;
  34 + public void setCallId(String callId) {
  35 + this.callId = callId;
35 36 }
36 37  
37   - public String getStreamId() {
38   - return streamId;
  38 + public String getStream() {
  39 + return stream;
39 40 }
40 41  
41   - public void setStreamId(String streamId) {
42   - this.streamId = streamId;
  42 + public void setStream(String stream) {
  43 + this.stream = stream;
43 44 }
44 45  
45 46 public byte[] getTransaction() {
... ... @@ -65,4 +66,12 @@ public class SsrcTransaction {
65 66 public void setMediaServerId(String mediaServerId) {
66 67 this.mediaServerId = mediaServerId;
67 68 }
  69 +
  70 + public String getSsrc() {
  71 + return ssrc;
  72 + }
  73 +
  74 + public void setSsrc(String ssrc) {
  75 + this.ssrc = ssrc;
  76 + }
68 77 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
... ... @@ -23,24 +23,36 @@ public class SipSubscribe {
23 23  
24 24 private Map<String, SipSubscribe.Event> okSubscribes = new ConcurrentHashMap<>();
25 25  
26   - private Map<String, Date> timeSubscribes = new ConcurrentHashMap<>();
  26 + private Map<String, Date> okTimeSubscribes = new ConcurrentHashMap<>();
  27 + private Map<String, Date> errorTimeSubscribes = new ConcurrentHashMap<>();
27 28  
28   -// @Scheduled(cron="*/5 * * * * ?") //每五秒执行一次
  29 + // @Scheduled(cron="*/5 * * * * ?") //每五秒执行一次
29 30 // @Scheduled(fixedRate= 100 * 60 * 60 )
30   - @Scheduled(cron="0 0 * * * ?") //每小时执行一次, 每个整点
  31 + @Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次
31 32 public void execute(){
32 33 logger.info("[定时任务] 清理过期的订阅信息");
33 34 Calendar calendar = Calendar.getInstance();
34 35 calendar.setTime(new Date());
35   - calendar.set(Calendar.HOUR, calendar.get(Calendar.HOUR) - 1);
36   - for (String key : timeSubscribes.keySet()) {
37   - if (timeSubscribes.get(key).before(calendar.getTime())){
38   - logger.info("[定时任务] 清理过期的订阅信息: {}", key);
39   - errorSubscribes.remove(key);
  36 + calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) - 5);
  37 +
  38 + for (String key : okTimeSubscribes.keySet()) {
  39 + if (okTimeSubscribes.get(key).before(calendar.getTime())){
  40 +// logger.info("[定时任务] 清理过期的订阅信息: {}", key);
40 41 okSubscribes.remove(key);
41   - timeSubscribes.remove(key);
  42 + okTimeSubscribes.remove(key);
  43 + }
  44 + }
  45 + for (String key : errorTimeSubscribes.keySet()) {
  46 + if (errorTimeSubscribes.get(key).before(calendar.getTime())){
  47 +// logger.info("[定时任务] 清理过期的订阅信息: {}", key);
  48 + errorSubscribes.remove(key);
  49 + errorTimeSubscribes.remove(key);
42 50 }
43 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());
44 56 }
45 57  
46 58 public interface Event {
... ... @@ -105,12 +117,12 @@ public class SipSubscribe {
105 117  
106 118 public void addErrorSubscribe(String key, SipSubscribe.Event event) {
107 119 errorSubscribes.put(key, event);
108   - timeSubscribes.put(key, new Date());
  120 + errorTimeSubscribes.put(key, new Date());
109 121 }
110 122  
111 123 public void addOkSubscribe(String key, SipSubscribe.Event event) {
112 124 okSubscribes.put(key, event);
113   - timeSubscribes.put(key, new Date());
  125 + okTimeSubscribes.put(key, new Date());
114 126 }
115 127  
116 128 public SipSubscribe.Event getErrorSubscribe(String key) {
... ... @@ -119,7 +131,7 @@ public class SipSubscribe {
119 131  
120 132 public void removeErrorSubscribe(String key) {
121 133 errorSubscribes.remove(key);
122   - timeSubscribes.remove(key);
  134 + errorTimeSubscribes.remove(key);
123 135 }
124 136  
125 137 public SipSubscribe.Event getOkSubscribe(String key) {
... ... @@ -128,7 +140,7 @@ public class SipSubscribe {
128 140  
129 141 public void removeOkSubscribe(String key) {
130 142 okSubscribes.remove(key);
131   - timeSubscribes.remove(key);
  143 + okTimeSubscribes.remove(key);
132 144 }
133 145 public int getErrorSubscribesSize(){
134 146 return errorSubscribes.size();
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
... ... @@ -14,6 +14,7 @@ import com.genersoft.iot.vmp.utils.redis.RedisUtil;
14 14 import gov.nist.javax.sip.stack.SIPDialog;
15 15 import org.springframework.beans.factory.annotation.Autowired;
16 16 import org.springframework.stereotype.Component;
  17 +import org.springframework.util.StringUtils;
17 18  
18 19 /**
19 20 * @description:视频流session管理器,管理视频预览、预览回放的通信句柄
... ... @@ -29,39 +30,55 @@ public class VideoStreamSessionManager {
29 30 @Autowired
30 31 private UserSetup userSetup;
31 32  
32   - public void put(String deviceId, String channelId ,String ssrc, String streamId, String mediaServerId, ClientTransaction transaction){
  33 + /**
  34 + * 添加一个点播/回放的事务信息
  35 + * 后续可以通过流Id/callID
  36 + * @param deviceId 设备ID
  37 + * @param channelId 通道ID
  38 + * @param callId 一次请求的CallID
  39 + * @param stream 流名称
  40 + * @param mediaServerId 所使用的流媒体ID
  41 + * @param transaction 事务
  42 + */
  43 + public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, ClientTransaction transaction){
33 44 SsrcTransaction ssrcTransaction = new SsrcTransaction();
34 45 ssrcTransaction.setDeviceId(deviceId);
35 46 ssrcTransaction.setChannelId(channelId);
36   - ssrcTransaction.setStreamId(streamId);
  47 + ssrcTransaction.setStream(stream);
37 48 byte[] transactionByteArray = SerializeUtils.serialize(transaction);
38 49 ssrcTransaction.setTransaction(transactionByteArray);
  50 + ssrcTransaction.setCallId(callId);
39 51 ssrcTransaction.setSsrc(ssrc);
40 52 ssrcTransaction.setMediaServerId(mediaServerId);
41 53  
42   - redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" + deviceId + "_" + channelId, ssrcTransaction);
  54 + redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId()
  55 + + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction);
  56 + redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId()
  57 + + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction);
43 58 }
44 59  
45   - public void put(String deviceId, String channelId , Dialog dialog){
46   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
  60 + public void put(String deviceId, String channelId, String callId, Dialog dialog){
  61 + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, null);
47 62 if (ssrcTransaction != null) {
48 63 byte[] dialogByteArray = SerializeUtils.serialize(dialog);
49 64 ssrcTransaction.setDialog(dialogByteArray);
50 65 }
51   - redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" + deviceId + "_" + channelId, ssrcTransaction);
  66 + redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId()
  67 + + "_" + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_"
  68 + + ssrcTransaction.getStream(), ssrcTransaction);
52 69 }
53 70  
54 71  
55   - public ClientTransaction getTransaction(String deviceId, String channelId){
56   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
  72 + public ClientTransaction getTransactionByStream(String deviceId, String channelId, String stream){
  73 + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
57 74 if (ssrcTransaction == null) return null;
58 75 byte[] transactionByteArray = ssrcTransaction.getTransaction();
59 76 ClientTransaction clientTransaction = (ClientTransaction)SerializeUtils.deSerialize(transactionByteArray);
60 77 return clientTransaction;
61 78 }
62 79  
63   - public SIPDialog getDialog(String deviceId, String channelId){
64   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
  80 + public SIPDialog getDialogByStream(String deviceId, String channelId, String stream){
  81 + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
65 82 if (ssrcTransaction == null) return null;
66 83 byte[] dialogByteArray = ssrcTransaction.getDialog();
67 84 if (dialogByteArray == null) return null;
... ... @@ -69,36 +86,37 @@ public class VideoStreamSessionManager {
69 86 return dialog;
70 87 }
71 88  
72   - public SsrcTransaction getSsrcTransaction(String deviceId, String channelId){
73   - SsrcTransaction ssrcTransaction = (SsrcTransaction)redisUtil.get(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" + deviceId + "_" + channelId);
74   - return ssrcTransaction;
  89 + public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){
  90 + if (StringUtils.isEmpty(callId)) callId ="*";
  91 + if (StringUtils.isEmpty(stream)) stream ="*";
  92 + String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream;
  93 + List<Object> scanResult = redisUtil.scan(key);
  94 + if (scanResult.size() == 0) return null;
  95 + return (SsrcTransaction)redisUtil.get((String) scanResult.get(0));
75 96 }
76 97  
77   - public String getStreamId(String deviceId, String channelId){
78   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
79   - if (ssrcTransaction == null) return null;
80   - return ssrcTransaction.getStreamId();
81   - }
82   - public String getMediaServerId(String deviceId, String channelId){
83   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
  98 + public String getMediaServerId(String deviceId, String channelId, String stream){
  99 + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
84 100 if (ssrcTransaction == null) return null;
85 101 return ssrcTransaction.getMediaServerId();
86 102 }
87 103  
88   - public String getSSRC(String deviceId, String channelId){
89   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
  104 + public String getSSRC(String deviceId, String channelId, String stream){
  105 + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
90 106 if (ssrcTransaction == null) return null;
91 107 return ssrcTransaction.getSsrc();
92 108 }
93 109  
94   - public void remove(String deviceId, String channelId) {
95   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
  110 + public void remove(String deviceId, String channelId, String stream) {
  111 + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
96 112 if (ssrcTransaction == null) return;
97   - redisUtil.del(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_" + deviceId + "_" + channelId);
  113 + redisUtil.del(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId() + "_"
  114 + + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream());
98 115 }
99 116  
  117 +
100 118 public List<SsrcTransaction> getAllSsrc() {
101   - List<Object> ssrcTransactionKeys = redisUtil.scan(String.format("%s_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetup.getServerId() + "_" ));
  119 + List<Object> ssrcTransactionKeys = redisUtil.scan(String.format("%s_*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetup.getServerId() + "_" ));
102 120 List<SsrcTransaction> result= new ArrayList<>();
103 121 for (int i = 0; i < ssrcTransactionKeys.size(); i++) {
104 122 String key = (String)ssrcTransactionKeys.get(i);
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
... ... @@ -119,8 +119,8 @@ public interface ISIPCommander {
119 119 /**
120 120 * 视频流停止
121 121 */
122   - void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent);
123   - void streamByeCmd(String deviceId, String channelId);
  122 + void streamByeCmd(String deviceId, String channelId, String ssrc, SipSubscribe.Event okEvent);
  123 + void streamByeCmd(String deviceId, String channelId, String ssrc);
124 124  
125 125 /**
126 126 * 回放暂停
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
... ... @@ -18,7 +18,7 @@ public interface ISIPCommanderForPlatform {
18 18 * @return
19 19 */
20 20 boolean register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent);
21   - boolean register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent);
  21 + boolean register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain);
22 22  
23 23 /**
24 24 * 向上级平台注销
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
... ... @@ -128,7 +128,15 @@ public class SIPRequestHeaderPlarformProvider {
128 128  
129 129  
130 130 Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(Request.REGISTER), fromTag, viaTag, callIdHeader);
131   -
  131 + SipURI requestURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
  132 + if (www == null) {
  133 + AuthorizationHeader authorizationHeader = sipFactory.createHeaderFactory().createAuthorizationHeader("Digest");
  134 + authorizationHeader.setUsername(parentPlatform.getDeviceGBId());
  135 + authorizationHeader.setURI(requestURI);
  136 + authorizationHeader.setAlgorithm("MD5");
  137 + registerRequest.addHeader(authorizationHeader);
  138 + return registerRequest;
  139 + }
132 140 String realm = www.getRealm();
133 141 String nonce = www.getNonce();
134 142 String scheme = www.getScheme();
... ... @@ -139,7 +147,6 @@ public class SIPRequestHeaderPlarformProvider {
139 147  
140 148 callIdHeader.setCallId(callId);
141 149  
142   - SipURI requestURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
143 150 String cNonce = null;
144 151 String nc = "00000001";
145 152 if (qop != null) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
... ... @@ -226,7 +226,7 @@ public class SIPRequestHeaderProvider {
226 226 throws PeerUnavailableException, ParseException, InvalidArgumentException {
227 227 Request request = null;
228 228 if (streamInfo == null) return null;
229   - Dialog dialog = streamSession.getDialog(streamInfo.getDeviceID(), streamInfo.getChannelId());
  229 + Dialog dialog = streamSession.getDialogByStream(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream());
230 230  
231 231 SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(),
232 232 device.getHostAddress());
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
... ... @@ -331,7 +331,7 @@ public class SIPCommander implements ISIPCommander {
331 331 */
332 332 @Override
333 333 public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
334   - String streamId = ssrcInfo.getStreamId();
  334 + String streamId = ssrcInfo.getStream();
335 335 try {
336 336 if (device == null) return;
337 337 String streamMode = device.getStreamMode().toUpperCase();
... ... @@ -407,6 +407,8 @@ public class SIPCommander implements ISIPCommander {
407 407 }
408 408  
409 409 content.append("y="+ssrcInfo.getSsrc()+"\r\n");//ssrc
  410 + // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
  411 +// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备
410 412  
411 413 String tm = Long.toString(System.currentTimeMillis());
412 414  
... ... @@ -415,14 +417,14 @@ public class SIPCommander implements ISIPCommander {
415 417  
416 418 Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrcInfo.getSsrc(), callIdHeader);
417 419  
418   - String finalStreamId = streamId;
419 420 transmitRequest(device, request, (e -> {
420   - streamSession.remove(device.getDeviceId(), channelId);
  421 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
421 422 mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc());
422 423 errorEvent.response(e);
423 424 }), e ->{
424   - streamSession.put(device.getDeviceId(), channelId ,ssrcInfo.getSsrc(), finalStreamId, mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction());
425   - streamSession.put(device.getDeviceId(), channelId , e.dialog);
  425 + // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
  426 + streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction());
  427 + streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog);
426 428 });
427 429  
428 430  
... ... @@ -444,12 +446,12 @@ public class SIPCommander implements ISIPCommander {
444 446 , SipSubscribe.Event errorEvent) {
445 447 try {
446 448  
447   - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
  449 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
448 450  
449 451 // 添加订阅
450 452 JSONObject subscribeKey = new JSONObject();
451 453 subscribeKey.put("app", "rtp");
452   - subscribeKey.put("stream", ssrcInfo.getStreamId());
  454 + subscribeKey.put("stream", ssrcInfo.getStream());
453 455 subscribeKey.put("regist", true);
454 456 subscribeKey.put("mediaServerId", mediaServerItem.getId());
455 457 logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
... ... @@ -530,8 +532,8 @@ public class SIPCommander implements ISIPCommander {
530 532  
531 533 transmitRequest(device, request, errorEvent, okEvent -> {
532 534 ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
533   - streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), responseEvent.getClientTransaction());
534   - streamSession.put(device.getDeviceId(), channelId, okEvent.dialog);
  535 + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction());
  536 + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
535 537 });
536 538 } catch ( SipException | ParseException | InvalidArgumentException e) {
537 539 e.printStackTrace();
... ... @@ -551,12 +553,12 @@ public class SIPCommander implements ISIPCommander {
551 553 public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event
552 554 , SipSubscribe.Event errorEvent) {
553 555 try {
554   - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
  556 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
555 557  
556 558 // 添加订阅
557 559 JSONObject subscribeKey = new JSONObject();
558 560 subscribeKey.put("app", "rtp");
559   - subscribeKey.put("stream", ssrcInfo.getStreamId());
  561 + subscribeKey.put("stream", ssrcInfo.getStream());
560 562 subscribeKey.put("regist", true);
561 563 subscribeKey.put("mediaServerId", mediaServerItem.getId());
562 564 logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
... ... @@ -637,7 +639,8 @@ public class SIPCommander implements ISIPCommander {
637 639 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
638 640  
639 641 ClientTransaction transaction = transmitRequest(device, request, errorEvent);
640   - streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), transaction);
  642 + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), transaction);
  643 + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), transaction);
641 644  
642 645 } catch ( SipException | ParseException | InvalidArgumentException e) {
643 646 e.printStackTrace();
... ... @@ -648,17 +651,17 @@ public class SIPCommander implements ISIPCommander {
648 651 * 视频流停止, 不使用回调
649 652 */
650 653 @Override
651   - public void streamByeCmd(String deviceId, String channelId) {
652   - streamByeCmd(deviceId, channelId, null);
  654 + public void streamByeCmd(String deviceId, String channelId, String stream) {
  655 + streamByeCmd(deviceId, channelId, stream, null);
653 656 }
654 657  
655 658 /**
656 659 * 视频流停止
657 660 */
658 661 @Override
659   - public void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent) {
  662 + public void streamByeCmd(String deviceId, String channelId, String stream, SipSubscribe.Event okEvent) {
660 663 try {
661   - ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId);
  664 + ClientTransaction transaction = streamSession.getTransactionByStream(deviceId, channelId, stream);
662 665 if (transaction == null) {
663 666 logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
664 667 SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>();
... ... @@ -667,7 +670,7 @@ public class SIPCommander implements ISIPCommander {
667 670 }
668 671 return;
669 672 }
670   - SIPDialog dialog = streamSession.getDialog(deviceId, channelId);
  673 + SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, stream);
671 674 if (dialog == null) {
672 675 logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId);
673 676 return;
... ... @@ -711,11 +714,11 @@ public class SIPCommander implements ISIPCommander {
711 714  
712 715 dialog.sendRequest(clientTransaction);
713 716  
714   - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId);
  717 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, callIdHeader.getCallId(), null);
715 718 if (ssrcTransaction != null) {
716 719 MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
717 720 mediaServerService.releaseSsrc(mediaServerItem, ssrcTransaction.getSsrc());
718   - streamSession.remove(deviceId, channelId);
  721 + streamSession.remove(deviceId, channelId, ssrcTransaction.getStream());
719 722 }
720 723 } catch (SipException | ParseException e) {
721 724 e.printStackTrace();
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
... ... @@ -52,7 +52,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
52 52  
53 53 @Override
54 54 public boolean register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) {
55   - return register(parentPlatform, null, null, errorEvent, okEvent);
  55 + return register(parentPlatform, null, null, errorEvent, okEvent, false);
56 56 }
57 57  
58 58 @Override
... ... @@ -64,15 +64,16 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
64 64 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
65 65 }
66 66  
67   - return register(parentPlatform, null, null, errorEvent, okEvent);
  67 + return register(parentPlatform, null, null, errorEvent, okEvent, false);
68 68 }
69 69  
70 70 @Override
71   - public boolean register(ParentPlatform parentPlatform, @Nullable String callId, @Nullable WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) {
  71 + public boolean register(ParentPlatform parentPlatform, @Nullable String callId, @Nullable WWWAuthenticateHeader www,
  72 + SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain) {
72 73 try {
73 74 Request request = null;
74 75 String tm = Long.toString(System.currentTimeMillis());
75   - if (www == null ) {
  76 + if (!registerAgain ) {
76 77 // //callid
77 78 CallIdHeader callIdHeader = null;
78 79 if(parentPlatform.getTransport().equals("TCP")) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
... ... @@ -87,7 +87,11 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
87 87 if (streamInfo == null) {
88 88 streamInfo = new StreamInfo();
89 89 streamInfo.setApp(sendRtpItem.getApp());
90   - streamInfo.setStreamId(sendRtpItem.getStreamId());
  90 + streamInfo.setStream(sendRtpItem.getStreamId());
  91 + }else {
  92 + streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
  93 + sendRtpItem.setStreamId(streamInfo.getStream());
  94 + streamInfo.setApp("rtp");
91 95 }
92 96 redisCatchStorage.updateSendRTPSever(sendRtpItem);
93 97 logger.info(platformGbId);
... ... @@ -95,7 +99,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
95 99 Map<String, Object> param = new HashMap<>();
96 100 param.put("vhost","__defaultVhost__");
97 101 param.put("app",streamInfo.getApp());
98   - param.put("stream",streamInfo.getStreamId());
  102 + param.put("stream",streamInfo.getStream());
99 103 param.put("ssrc", sendRtpItem.getSsrc());
100 104 param.put("dst_url",sendRtpItem.getIp());
101 105 param.put("dst_port", sendRtpItem.getPort());
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
... ... @@ -111,7 +111,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
111 111 }
112 112  
113 113 storager.stopPlay(device.getDeviceId(), channelId);
114   - mediaServerService.closeRTPServer(device, channelId);
  114 + mediaServerService.closeRTPServer(device, channelId, streamInfo.getStream());
115 115 }
116 116 }
117 117 } catch (SipException e) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
... ... @@ -68,6 +68,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
68 68 }
69 69 if (device.getPort() != rPort) {
70 70 device.setPort(rPort);
  71 + device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));
71 72 videoManagerStorager.updateDevice(device);
72 73 redisCatchStorage.updateDevice(device);
73 74 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
... ... @@ -62,7 +62,7 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
62 62 StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(device.getDeviceId(), "*");
63 63 if (streamInfo != null) {
64 64 redisCatchStorage.stopPlayback(streamInfo);
65   - cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId());
  65 + cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream());
66 66 }
67 67 }
68 68 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java
... ... @@ -78,7 +78,7 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
78 78  
79 79 if (response.getStatusCode() == 401) {
80 80 WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME);
81   - sipCommanderForPlatform.register(parentPlatform, callId, www, null, null);
  81 + sipCommanderForPlatform.register(parentPlatform, callId, www, null, null, true);
82 82 }else if (response.getStatusCode() == 200){
83 83 // 注册/注销成功
84 84 logger.info(String.format("%s %s成功", platformGBId, action));
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -360,6 +360,7 @@ public class ZLMHttpHookListener {
360 360 StreamPushItem streamPushItem = null;
361 361 StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, streamId, tracks);
362 362 item.setStreamInfo(streamInfoByAppAndStream);
  363 +
363 364 redisCatchStorage.addStream(mediaServerItem, type, app, streamId, item);
364 365 if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal()
365 366 || item.getOriginType() == OriginType.RTMP_PUSH.ordinal()
... ... @@ -438,14 +439,16 @@ public class ZLMHttpHookListener {
438 439 if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) {
439 440 ret.put("close", false);
440 441 } else {
441   - cmder.streamByeCmd(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId());
  442 + cmder.streamByeCmd(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId(),
  443 + streamInfoForPlayCatch.getStream());
442 444 redisCatchStorage.stopPlay(streamInfoForPlayCatch);
443 445 storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId());
444 446 }
445 447 }else{
446 448 StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlaybackByStreamId(streamId);
447 449 if (streamInfoForPlayBackCatch != null) {
448   - cmder.streamByeCmd(streamInfoForPlayBackCatch.getDeviceID(), streamInfoForPlayBackCatch.getChannelId());
  450 + cmder.streamByeCmd(streamInfoForPlayBackCatch.getDeviceID(),
  451 + streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream());
449 452 redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch);
450 453 }else {
451 454 StreamInfo streamInfoForDownload = redisCatchStorage.queryDownloadByStreamId(streamId);
... ...
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
... ... @@ -46,7 +46,7 @@ public interface IMediaServerService {
46 46  
47 47 SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean isPlayback);
48 48  
49   - void closeRTPServer(Device device, String channelId);
  49 + void closeRTPServer(Device device, String channelId, String ssrc);
50 50  
51 51 void clearRTPServer(MediaServerItem mediaServerItem);
52 52  
... ...
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
... ... @@ -5,14 +5,16 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
5 5 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6 6 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
7 7 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  8 +import com.genersoft.iot.vmp.service.bean.PlayBackCallback;
8 9 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
  10 +import org.springframework.http.ResponseEntity;
  11 +import org.springframework.web.context.request.async.DeferredResult;
9 12  
10 13 /**
11 14 * 点播处理
12 15 */
13 16 public interface IPlayService {
14 17  
15   - void onPublishHandlerForPlayBack(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid);
16 18 void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid);
17 19  
18 20 PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
... ... @@ -20,4 +22,6 @@ public interface IPlayService {
20 22 MediaServerItem getNewMediaServerItem(Device device);
21 23  
22 24 void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String toString);
  25 +
  26 + DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, PlayBackCallback errorCallBack);
23 27 }
... ...
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.bean;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  4 +
  5 +public interface PlayBackCallback {
  6 +
  7 + void call(RequestMessage msg);
  8 +
  9 +}
... ...
src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java
... ... @@ -4,12 +4,12 @@ public class SSRCInfo {
4 4  
5 5 private int port;
6 6 private String ssrc;
7   - private String StreamId;
  7 + private String Stream;
8 8  
9   - public SSRCInfo(int port, String ssrc, String streamId) {
  9 + public SSRCInfo(int port, String ssrc, String stream) {
10 10 this.port = port;
11 11 this.ssrc = ssrc;
12   - StreamId = streamId;
  12 + Stream = stream;
13 13 }
14 14  
15 15 public int getPort() {
... ... @@ -28,11 +28,11 @@ public class SSRCInfo {
28 28 this.ssrc = ssrc;
29 29 }
30 30  
31   - public String getStreamId() {
32   - return StreamId;
  31 + public String getStream() {
  32 + return Stream;
33 33 }
34 34  
35   - public void setStreamId(String streamId) {
36   - StreamId = streamId;
  35 + public void setStream(String stream) {
  36 + Stream = stream;
37 37 }
38 38 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
... ... @@ -162,15 +162,16 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
162 162 }
163 163  
164 164 @Override
165   - public void closeRTPServer(Device device, String channelId) {
166   - String mediaServerId = streamSession.getMediaServerId(device.getDeviceId(), channelId);
  165 + public void closeRTPServer(Device device, String channelId, String stream) {
  166 + String mediaServerId = streamSession.getMediaServerId(device.getDeviceId(), channelId, stream);
  167 + String ssrc = streamSession.getSSRC(device.getDeviceId(), channelId, stream);
167 168 MediaServerItem mediaServerItem = this.getOne(mediaServerId);
168 169 if (mediaServerItem != null) {
169 170 String streamId = String.format("%s_%s", device.getDeviceId(), channelId);
170 171 zlmrtpServerFactory.closeRTPServer(mediaServerItem, streamId);
171   - releaseSsrc(mediaServerItem, streamSession.getSSRC(device.getDeviceId(), channelId));
  172 + releaseSsrc(mediaServerItem, ssrc);
172 173 }
173   - streamSession.remove(device.getDeviceId(), channelId);
  174 + streamSession.remove(device.getDeviceId(), channelId, stream);
174 175 }
175 176  
176 177 @Override
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
... ... @@ -74,7 +74,7 @@ public class MediaServiceImpl implements IMediaService {
74 74 @Override
75 75 public StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks, String addr) {
76 76 StreamInfo streamInfoResult = new StreamInfo();
77   - streamInfoResult.setStreamId(stream);
  77 + streamInfoResult.setStream(stream);
78 78 streamInfoResult.setApp(app);
79 79 if (addr == null) {
80 80 addr = mediaInfo.getStreamIp();
... ...
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.PlayBackCallback;
19 20 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
20 21 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
21 22 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
... ... @@ -104,19 +105,21 @@ public class PlayServiceImpl implements IPlayService {
104 105 logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
105 106 WVPResult wvpResult = new WVPResult();
106 107 wvpResult.setCode(-1);
107   - SIPDialog dialog = streamSession.getDialog(deviceId, channelId);
  108 + SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, streamInfo.getStream());
108 109 if (dialog != null) {
109 110 wvpResult.setMsg("收流超时,请稍候重试");
110 111 }else {
111 112 wvpResult.setMsg("点播超时,请稍候重试");
112 113 }
  114 +
113 115 msg.setData(wvpResult);
114 116 // 点播超时回复BYE
115   - cmder.streamByeCmd(device.getDeviceId(), channelId);
  117 + cmder.streamByeCmd(device.getDeviceId(), channelId, streamInfo.getStream());
116 118 // 释放rtpserver
117   - mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
  119 + mediaServerService.closeRTPServer(playResult.getDevice(), channelId, streamInfo.getStream());
118 120 // 回复之前所有的点播请求
119 121 resultHolder.invokeAllResult(msg);
  122 + // TODO 释放ssrc
120 123 });
121 124 result.onCompletion(()->{
122 125 // 点播结束时调用截图接口
... ... @@ -153,14 +156,12 @@ public class PlayServiceImpl implements IPlayService {
153 156 }
154 157 });
155 158 if (streamInfo == null) {
156   - SSRCInfo ssrcInfo;
157 159 String streamId = null;
158 160 if (mediaServerItem.isRtpEnable()) {
159 161 streamId = String.format("%s_%s", device.getDeviceId(), channelId);
160 162 }
161 163  
162   - ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId);
163   -
  164 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId);
164 165 // 发送点播消息
165 166 cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
166 167 logger.info("收到订阅消息: " + response.toJSONString());
... ... @@ -172,7 +173,7 @@ public class PlayServiceImpl implements IPlayService {
172 173 WVPResult wvpResult = new WVPResult();
173 174 wvpResult.setCode(-1);
174 175 // 点播返回sip错误
175   - mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
  176 + mediaServerService.closeRTPServer(playResult.getDevice(), channelId, ssrcInfo.getStream());
176 177 wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg));
177 178 msg.setData(wvpResult);
178 179 resultHolder.invokeAllResult(msg);
... ... @@ -183,7 +184,7 @@ public class PlayServiceImpl implements IPlayService {
183 184  
184 185 });
185 186 } else {
186   - String streamId = streamInfo.getStreamId();
  187 + String streamId = streamInfo.getStream();
187 188 if (streamId == null) {
188 189 WVPResult wvpResult = new WVPResult();
189 190 wvpResult.setCode(-1);
... ... @@ -212,18 +213,16 @@ public class PlayServiceImpl implements IPlayService {
212 213 // TODO 点播前是否重置状态
213 214 redisCatchStorage.stopPlay(streamInfo);
214 215 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
215   - SSRCInfo ssrcInfo;
216 216 String streamId2 = null;
217 217 if (mediaServerItem.isRtpEnable()) {
218 218 streamId2 = String.format("%s_%s", device.getDeviceId(), channelId);
219 219 }
220   - ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId2);
221   -
  220 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId2);
222 221 cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
223 222 logger.info("收到订阅消息: " + response.toJSONString());
224 223 onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid);
225 224 }, (event) -> {
226   - mediaServerService.closeRTPServer(playResult.getDevice(), channelId);
  225 + mediaServerService.closeRTPServer(playResult.getDevice(), channelId, ssrcInfo.getStream());
227 226 WVPResult wvpResult = new WVPResult();
228 227 wvpResult.setCode(-1);
229 228 wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg));
... ... @@ -241,12 +240,12 @@ public class PlayServiceImpl implements IPlayService {
241 240 RequestMessage msg = new RequestMessage();
242 241 msg.setId(uuid);
243 242 msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId);
244   - StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId, uuid);
  243 + StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId);
245 244 if (streamInfo != null) {
246 245 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
247 246 if (deviceChannel != null) {
248   - deviceChannel.setStreamId(streamInfo.getStreamId());
249   - storager.startPlay(deviceId, channelId, streamInfo.getStreamId());
  247 + deviceChannel.setStreamId(streamInfo.getStream());
  248 + storager.startPlay(deviceId, channelId, streamInfo.getStream());
250 249 }
251 250 redisCatchStorage.startPlay(streamInfo);
252 251 msg.setData(JSON.toJSONString(streamInfo));
... ... @@ -283,29 +282,53 @@ public class PlayServiceImpl implements IPlayService {
283 282  
284 283  
285 284 @Override
286   - public void onPublishHandlerForPlayBack(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
  285 + public DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, PlayBackCallback callback) {
  286 + String uuid = UUID.randomUUID().toString();
  287 + String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
  288 + DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(30000L);
  289 + Device device = storager.queryVideoDevice(deviceId);
  290 + if (device == null) {
  291 + result.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
  292 + return result;
  293 + }
  294 +
  295 + MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
  296 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true);
  297 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId, uuid, result);
287 298 RequestMessage msg = new RequestMessage();
288   - msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId);
289 299 msg.setId(uuid);
290   - StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId, uuid);
291   - if (streamInfo != null) {
  300 + msg.setKey(key);
  301 + result.onTimeout(()->{
  302 + msg.setData("回放超时");
  303 + callback.call(msg);
  304 + });
  305 + cmder.playbackStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, (MediaServerItem mediaServerItem, JSONObject response) -> {
  306 + logger.info("收到订阅消息: " + response.toJSONString());
  307 + StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
  308 + if (streamInfo == null) {
  309 + logger.warn("设备回放API调用失败!");
  310 + msg.setData("设备回放API调用失败!");
  311 + callback.call(msg);
  312 + return;
  313 + }
292 314 redisCatchStorage.startPlayback(streamInfo);
293 315 msg.setData(JSON.toJSONString(streamInfo));
294   - resultHolder.invokeResult(msg);
295   - } else {
296   - logger.warn("设备回放API调用失败!");
297   - msg.setData("设备回放API调用失败!");
298   - resultHolder.invokeResult(msg);
299   - }
  316 + callback.call(msg);
  317 + }, event -> {
  318 + msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
  319 + callback.call(msg);
  320 + });
  321 + return result;
300 322 }
301 323  
302 324  
  325 +
303 326 @Override
304 327 public void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) {
305 328 RequestMessage msg = new RequestMessage();
306 329 msg.setKey(DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId);
307 330 msg.setId(uuid);
308   - StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId, uuid);
  331 + StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
309 332 if (streamInfo != null) {
310 333 redisCatchStorage.startDownload(streamInfo);
311 334 msg.setData(JSON.toJSONString(streamInfo));
... ... @@ -318,7 +341,7 @@ public class PlayServiceImpl implements IPlayService {
318 341 }
319 342  
320 343  
321   - public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
  344 + public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId) {
322 345 String streamId = resonse.getString("stream");
323 346 JSONArray tracks = resonse.getJSONArray("tracks");
324 347 StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem,"rtp", streamId, tracks);
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
... ... @@ -132,7 +132,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
132 132 }else {
133 133 streamLive = true;
134 134 StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(
135   - mediaInfo, param.getApp(), param.getStream(), null);
  135 + mediaInfo, param.getApp(), param.getStream(), null, null);
136 136 wvpResult.setData(streamInfo);
137 137  
138 138 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
... ... @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
7 7 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
8 8 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
9 9 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
  10 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
10 11 import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
11 12  
12 13 import java.util.List;
... ... @@ -220,4 +221,5 @@ public interface IRedisCatchStorage {
220 221 void addMemInfo(double memInfo);
221 222  
222 223 void addNetInfo(Map<String, String> networkInterfaces);
  224 +
223 225 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
... ... @@ -10,15 +10,16 @@ import java.util.List;
10 10 @Repository
11 11 public interface StreamProxyMapper {
12 12  
13   - @Insert("INSERT INTO stream_proxy (type, app, stream,mediaServerId, url, src_url, dst_url, " +
  13 + @Insert("INSERT INTO stream_proxy (type, name, app, stream,mediaServerId, url, src_url, dst_url, " +
14 14 "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable, status, enable_remove_none_reader, createTime) VALUES" +
15   - "('${type}','${app}', '${stream}', '${mediaServerId}','${url}', '${src_url}', '${dst_url}', " +
  15 + "('${type}','${name}', '${app}', '${stream}', '${mediaServerId}','${url}', '${src_url}', '${dst_url}', " +
16 16 "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable}, ${status}, " +
17 17 "${enable_remove_none_reader}, '${createTime}' )")
18 18 int add(StreamProxyItem streamProxyDto);
19 19  
20 20 @Update("UPDATE stream_proxy " +
21 21 "SET type=#{type}, " +
  22 + "name=#{name}," +
22 23 "app=#{app}," +
23 24 "stream=#{stream}," +
24 25 "url=#{url}, " +
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
... ... @@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
10 10 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
11 11 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
12 12 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
  13 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
13 14 import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
14 15 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
15 16 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
... ... @@ -91,7 +92,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
91 92 */
92 93 @Override
93 94 public boolean startPlay(StreamInfo stream) {
94   - return redis.set(String.format("%S_%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, userSetup.getServerId(), stream.getStreamId(),stream.getDeviceID(), stream.getChannelId()),
  95 + return redis.set(String.format("%S_%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, userSetup.getServerId(),
  96 + stream.getStream(), stream.getDeviceID(), stream.getChannelId()),
95 97 stream);
96 98 }
97 99  
... ... @@ -105,7 +107,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
105 107 if (streamInfo == null) return false;
106 108 return redis.del(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
107 109 userSetup.getServerId(),
108   - streamInfo.getStreamId(),
  110 + streamInfo.getStream(),
109 111 streamInfo.getDeviceID(),
110 112 streamInfo.getChannelId()));
111 113 }
... ... @@ -119,7 +121,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
119 121 return (StreamInfo)redis.get(String.format("%S_%s_%s_%s_%s",
120 122 VideoManagerConstants.PLAYER_PREFIX,
121 123 userSetup.getServerId(),
122   - streamInfo.getStreamId(),
  124 + streamInfo.getStream(),
123 125 streamInfo.getDeviceID(),
124 126 streamInfo.getChannelId()));
125 127 }
... ... @@ -164,14 +166,14 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
164 166  
165 167 @Override
166 168 public boolean startPlayback(StreamInfo stream) {
167   - return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, userSetup.getServerId(),stream.getStreamId(),
168   - stream.getDeviceID(), stream.getChannelId()), stream);
  169 + return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
  170 + userSetup.getServerId(), stream.getStream(), stream.getDeviceID(), stream.getChannelId()), stream);
169 171 }
170 172  
171 173 @Override
172 174 public boolean startDownload(StreamInfo streamInfo) {
173   - return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, userSetup.getServerId(),streamInfo.getStreamId(),
174   - streamInfo.getDeviceID(), streamInfo.getChannelId()), streamInfo);
  175 + return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, userSetup.getServerId(),
  176 + streamInfo.getStream(), streamInfo.getDeviceID(), streamInfo.getChannelId()), streamInfo);
175 177 }
176 178  
177 179 @Override
... ... @@ -185,7 +187,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
185 187 }
186 188 return redis.del(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
187 189 userSetup.getServerId(),
188   - streamInfo.getStreamId(),
  190 + streamInfo.getStream(),
189 191 streamInfo.getDeviceID(),
190 192 streamInfo.getChannelId()));
191 193 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
1 1 package com.genersoft.iot.vmp.storager.impl;
2 2  
  3 +import com.genersoft.iot.vmp.common.StreamInfo;
3 4 import com.genersoft.iot.vmp.conf.SipConfig;
4 5 import com.genersoft.iot.vmp.gb28181.bean.*;
5 6 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
... ... @@ -157,7 +158,10 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
157 158 public synchronized void updateChannel(String deviceId, DeviceChannel channel) {
158 159 String channelId = channel.getChannelId();
159 160 channel.setDeviceId(deviceId);
160   - channel.setStreamId(streamSession.getStreamId(deviceId, channel.getChannelId()));
  161 + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
  162 + if (streamInfo != null) {
  163 + channel.setStreamId(streamInfo.getStream());
  164 + }
161 165 String now = this.format.format(System.currentTimeMillis());
162 166 channel.setUpdateTime(now);
163 167 DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);
... ... @@ -179,7 +183,10 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
179 183 if (channelList.size() == 0) {
180 184 for (DeviceChannel channel : channels) {
181 185 channel.setDeviceId(deviceId);
182   - channel.setStreamId(streamSession.getStreamId(deviceId, channel.getChannelId()));
  186 + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId());
  187 + if (streamInfo != null) {
  188 + channel.setStreamId(streamInfo.getStream());
  189 + }
183 190 String now = this.format.format(System.currentTimeMillis());
184 191 channel.setUpdateTime(now);
185 192 channel.setCreateTime(now);
... ... @@ -190,9 +197,11 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
190 197 channelsInStore.put(deviceChannel.getChannelId(), deviceChannel);
191 198 }
192 199 for (DeviceChannel channel : channels) {
193   - String channelId = channel.getChannelId();
194 200 channel.setDeviceId(deviceId);
195   - channel.setStreamId(streamSession.getStreamId(deviceId, channel.getChannelId()));
  201 + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId());
  202 + if (streamInfo != null) {
  203 + channel.setStreamId(streamInfo.getStream());
  204 + }
196 205 String now = this.format.format(System.currentTimeMillis());
197 206 channel.setUpdateTime(now);
198 207 if (channelsInStore.get(channel.getChannelId()) != null) {
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
... ... @@ -110,26 +110,26 @@ public class PlayController {
110 110 String key = DeferredResultHolder.CALLBACK_CMD_STOP + deviceId + channelId;
111 111 resultHolder.put(key, uuid, result);
112 112 Device device = storager.queryVideoDevice(deviceId);
113   - cmder.streamByeCmd(deviceId, channelId, (event) -> {
114   - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
115   - if (streamInfo == null) {
116   - RequestMessage msg = new RequestMessage();
117   - msg.setId(uuid);
118   - msg.setKey(key);
119   - msg.setData("点播未找到");
120   - resultHolder.invokeAllResult(msg);
121   - storager.stopPlay(deviceId, channelId);
122   - }else {
123   - redisCatchStorage.stopPlay(streamInfo);
124   - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
125   - RequestMessage msg = new RequestMessage();
126   - msg.setId(uuid);
127   - msg.setKey(key);
128   - //Response response = event.getResponse();
129   - msg.setData(String.format("success"));
130   - resultHolder.invokeAllResult(msg);
131   - }
132   - mediaServerService.closeRTPServer(device, channelId);
  113 + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
  114 + if (streamInfo == null) {
  115 + RequestMessage msg = new RequestMessage();
  116 + msg.setId(uuid);
  117 + msg.setKey(key);
  118 + msg.setData("点播未找到");
  119 + resultHolder.invokeAllResult(msg);
  120 + storager.stopPlay(deviceId, channelId);
  121 + return result;
  122 + }
  123 + cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream(), (event) -> {
  124 + redisCatchStorage.stopPlay(streamInfo);
  125 + storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
  126 + RequestMessage msg = new RequestMessage();
  127 + msg.setId(uuid);
  128 + msg.setKey(key);
  129 + //Response response = event.getResponse();
  130 + msg.setData(String.format("success"));
  131 + resultHolder.invokeAllResult(msg);
  132 + mediaServerService.closeRTPServer(device, channelId, streamInfo.getStream());
133 133 });
134 134  
135 135 if (deviceId != null || channelId != null) {
... ... @@ -329,7 +329,7 @@ public class PlayController {
329 329 jsonObject.put("deviceId", transaction.getDeviceId());
330 330 jsonObject.put("channelId", transaction.getChannelId());
331 331 jsonObject.put("ssrc", transaction.getSsrc());
332   - jsonObject.put("streamId", transaction.getStreamId());
  332 + jsonObject.put("streamId", transaction.getStream());
333 333 objects.add(jsonObject);
334 334 }
335 335  
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/DownloadController.java
... ... @@ -96,7 +96,7 @@ public class DownloadController {
96 96 StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId);
97 97 if (streamInfo != null) {
98 98 // 停止之前的下载
99   - cmder.streamByeCmd(deviceId, channelId);
  99 + cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream());
100 100 }
101 101  
102 102 MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
... ... @@ -114,7 +114,7 @@ public class DownloadController {
114 114  
115 115 cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (MediaServerItem mediaServerItem, JSONObject response) -> {
116 116 logger.info("收到订阅消息: " + response.toJSONString());
117   - playService.onPublishHandlerForDownload(mediaServerItem, response, deviceId, channelId, uuid.toString());
  117 + playService.onPublishHandlerForDownload(mediaServerItem, response, deviceId, channelId, uuid);
118 118 }, event -> {
119 119 RequestMessage msg = new RequestMessage();
120 120 msg.setId(uuid);
... ... @@ -130,11 +130,12 @@ public class DownloadController {
130 130 @ApiImplicitParams({
131 131 @ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
132 132 @ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class),
  133 + @ApiImplicitParam(name = "stream", value = "流ID", dataTypeClass = String.class),
133 134 })
134   - @GetMapping("/stop/{deviceId}/{channelId}")
135   - public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId) {
  135 + @GetMapping("/stop/{deviceId}/{channelId}/{stream}")
  136 + public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) {
136 137  
137   - cmder.streamByeCmd(deviceId, channelId);
  138 + cmder.streamByeCmd(deviceId, channelId, stream);
138 139  
139 140 if (logger.isDebugEnabled()) {
140 141 logger.debug(String.format("设备历史媒体下载停止 API调用,deviceId/channelId:%s_%s", deviceId, channelId));
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
... ... @@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory;
18 18 import org.springframework.beans.factory.annotation.Autowired;
19 19 import org.springframework.http.HttpStatus;
20 20 import org.springframework.http.ResponseEntity;
  21 +import org.springframework.util.StringUtils;
21 22 import org.springframework.web.bind.annotation.CrossOrigin;
22 23 import org.springframework.web.bind.annotation.GetMapping;
23 24 import org.springframework.web.bind.annotation.PathVariable;
... ... @@ -75,52 +76,8 @@ public class PlaybackController {
75 76 if (logger.isDebugEnabled()) {
76 77 logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId));
77 78 }
78   - String uuid = UUID.randomUUID().toString();
79   - String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
80   - DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(30000L);
81   - Device device = storager.queryVideoDevice(deviceId);
82   - if (device == null) {
83   - result.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
84   - return result;
85   - }
86   - MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
87   - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true);
88   -
89   - // 超时处理
90   - result.onTimeout(()->{
91   - logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
92   - RequestMessage msg = new RequestMessage();
93   - msg.setId(uuid);
94   - msg.setKey(key);
95   - msg.setData("Timeout");
96   - resultHolder.invokeResult(msg);
97   - });
98   -
99   - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId);
100   - if (streamInfo != null) {
101   - // 停止之前的回放
102   - cmder.streamByeCmd(deviceId, channelId);
103   - }
104   - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId, uuid, result);
105   -
106   - if (newMediaServerItem == null) {
107   - logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
108   - RequestMessage msg = new RequestMessage();
109   - msg.setId(uuid);
110   - msg.setKey(key);
111   - msg.setData("Timeout");
112   - resultHolder.invokeResult(msg);
113   - return result;
114   - }
115 79  
116   - cmder.playbackStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, (MediaServerItem mediaServerItem, JSONObject response) -> {
117   - logger.info("收到订阅消息: " + response.toJSONString());
118   - playService.onPublishHandlerForPlayBack(mediaServerItem, response, deviceId, channelId, uuid.toString());
119   - }, event -> {
120   - RequestMessage msg = new RequestMessage();
121   - msg.setId(uuid);
122   - msg.setKey(key);
123   - msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
  80 + DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, msg->{
124 81 resultHolder.invokeResult(msg);
125 82 });
126 83  
... ... @@ -131,24 +88,31 @@ public class PlaybackController {
131 88 @ApiImplicitParams({
132 89 @ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
133 90 @ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class),
  91 + @ApiImplicitParam(name = "stream", value = "流ID", dataTypeClass = String.class),
134 92 })
135   - @GetMapping("/stop/{deviceId}/{channelId}")
136   - public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId) {
  93 + @GetMapping("/stop/{deviceId}/{channelId}/{stream}")
  94 + public ResponseEntity<String> playStop(
  95 + @PathVariable String deviceId,
  96 + @PathVariable String channelId,
  97 + @PathVariable String stream) {
137 98  
138   - cmder.streamByeCmd(deviceId, channelId);
  99 + cmder.streamByeCmd(deviceId, channelId, stream);
139 100  
140 101 if (logger.isDebugEnabled()) {
141 102 logger.debug(String.format("设备录像回放停止 API调用,deviceId/channelId:%s/%s", deviceId, channelId));
142 103 }
  104 + if (StringUtils.isEmpty(deviceId) || StringUtils.isEmpty(channelId) || StringUtils.isEmpty(stream)) {
  105 + return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
  106 + }
143 107  
144 108 if (deviceId != null && channelId != null) {
145 109 JSONObject json = new JSONObject();
146 110 json.put("deviceId", deviceId);
147 111 json.put("channelId", channelId);
148   - return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
  112 + return new ResponseEntity<>(json.toString(), HttpStatus.OK);
149 113 } else {
150 114 logger.warn("设备录像回放停止API调用失败!");
151   - return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
  115 + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
152 116 }
153 117 }
154 118  
... ...
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
... ... @@ -103,7 +103,7 @@ public class ApiStreamController {
103 103 PlayResult play = playService.play(newMediaServerItem, serial, code, (mediaServerItem, response)->{
104 104 StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(serial, code);
105 105 JSONObject result = new JSONObject();
106   - result.put("StreamID", streamInfo.getStreamId());
  106 + result.put("StreamID", streamInfo.getStream());
107 107 result.put("DeviceID", device.getDeviceId());
108 108 result.put("ChannelID", code);
109 109 result.put("ChannelName", deviceChannel.getName());
... ... @@ -177,7 +177,7 @@ public class ApiStreamController {
177 177 result.put("error","未找到流信息");
178 178 return result;
179 179 }
180   - cmder.streamByeCmd(serial, code);
  180 + cmder.streamByeCmd(serial, code, streamInfo.getStream());
181 181 redisCatchStorage.stopPlay(streamInfo);
182 182 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
183 183 return null;
... ...
src/main/resources/all-application.yml
... ... @@ -186,7 +186,7 @@ user-settings:
186 186 # 是否将日志存储进数据库
187 187 logInDatebase: true
188 188 # 第三方匹配,用于从stream钟获取有效信息
189   - thirdPartyGBIdReg: [\s\S]*
  189 + thirdPartyGBIdReg: "[\\s\\S]*"
190 190  
191 191 # 在线文档: swagger-ui(生产环境建议关闭)
192 192 swagger-ui:
... ...
src/main/resources/logback-spring-local.xml
... ... @@ -83,7 +83,7 @@
83 83 <logger name="com.genersoft.iot.vmp.storager.dao" level="INFO">
84 84 <appender-ref ref="STDOUT"/>
85 85 </logger>
86   - <logger name="com.genersoft.iot.vmp.gb28181" level="DEBUG">
  86 + <logger name="com.genersoft.iot.vmp.gb28181" level="INFO">
87 87 <appender-ref ref="STDOUT"/>
88 88 </logger>
89 89  
... ...
web_src/src/components/dialog/changePassword.vue
... ... @@ -75,7 +75,10 @@ export default {
75 75 isLoging: false,
76 76 rules: {
77 77 oldPassword: [{ required: true, validator: validatePass0, trigger: "blur" }],
78   - newPassword: [{ required: true, validator: validatePass1, trigger: "blur" }],
  78 + newPassword: [{ required: true, validator: validatePass1, trigger: "blur" }, {
  79 + pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,.\/]).{8,20}$/,
  80 + message: "密码长度在8-20位之间,由字母+数字+特殊字符组成",
  81 + },],
79 82 confirmPassword: [{ required: true, validator: validatePass2, trigger: "blur" }],
80 83 },
81 84 };
... ...
web_src/src/components/dialog/devicePlayer.vue
... ... @@ -307,7 +307,7 @@ export default {
307 307 this.isLoging = false;
308 308 // this.videoUrl = streamInfo.rtc;
309 309 this.videoUrl = this.getUrlByStreamInfo(streamInfo);
310   - this.streamId = streamInfo.streamId;
  310 + this.streamId = streamInfo.stream;
311 311 this.app = streamInfo.app;
312 312 this.mediaServerId = streamInfo.mediaServerId;
313 313 this.playFromStreamInfo(false, streamInfo)
... ... @@ -485,8 +485,9 @@ export default {
485 485 }).then(function (res) {
486 486 var streamInfo = res.data;
487 487 that.app = streamInfo.app;
488   - that.streamId = streamInfo.streamId;
  488 + that.streamId = streamInfo.stream;
489 489 that.mediaServerId = streamInfo.mediaServerId;
  490 + that.ssrc = streamInfo.ssrc;
490 491 that.videoUrl = that.getUrlByStreamInfo(streamInfo);
491 492 that.recordPlay = true;
492 493 });
... ... @@ -497,7 +498,7 @@ export default {
497 498 this.videoUrl = '';
498 499 this.$axios({
499 500 method: 'get',
500   - url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId
  501 + url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId
501 502 }).then(function (res) {
502 503 if (callback) callback()
503 504 });
... ... @@ -517,7 +518,7 @@ export default {
517 518 }).then(function (res) {
518 519 var streamInfo = res.data;
519 520 that.app = streamInfo.app;
520   - that.streamId = streamInfo.streamId;
  521 + that.streamId = streamInfo.stream;
521 522 that.mediaServerId = streamInfo.mediaServerId;
522 523 that.videoUrl = that.getUrlByStreamInfo(streamInfo);
523 524 that.recordPlay = true;
... ... @@ -529,7 +530,7 @@ export default {
529 530 this.videoUrl = '';
530 531 this.$axios({
531 532 method: 'get',
532   - url: '/api/download/stop/' + this.deviceId + "/" + this.channelId
  533 + url: '/api/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.streamId
533 534 }).then(function (res) {
534 535 if (callback) callback()
535 536 });
... ... @@ -539,8 +540,6 @@ export default {
539 540 let that = this;
540 541 this.$axios({
541 542 method: 'post',
542   - // url: '/api/ptz/' + this.deviceId + '/' + this.channelId + '?leftRight=' + leftRight + '&upDown=' + upDown +
543   - // '&inOut=' + zoom + '&moveSpeed=50&zoomSpeed=50'
544 543 url: '/api/ptz/control/' + this.deviceId + '/' + this.channelId + '?command=' + command + '&horizonSpeed=' + this.controSpeed + '&verticalSpeed=' + this.controSpeed + '&zoomSpeed=' + this.controSpeed
545 544 }).then(function (res) {});
546 545 },
... ...