Commit f2279859b367fda6108a5ea22c572d38d89d338d

Authored by panlinlin
1 parent 17f4fe25

增加对水星IPC的兼容

增加对SIP错误的订阅,刷新通道或点播或回放出现sip错误时及时返回给页面
优化UI,增加按钮loading
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -8,8 +8,10 @@ import java.util.concurrent.ThreadPoolExecutor; @@ -8,8 +8,10 @@ import java.util.concurrent.ThreadPoolExecutor;
8 import java.util.concurrent.TimeUnit; 8 import java.util.concurrent.TimeUnit;
9 9
10 import javax.sip.*; 10 import javax.sip.*;
  11 +import javax.sip.header.CallIdHeader;
11 import javax.sip.message.Response; 12 import javax.sip.message.Response;
12 13
  14 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
13 import org.slf4j.Logger; 15 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory; 16 import org.slf4j.LoggerFactory;
15 import org.springframework.beans.factory.annotation.Autowired; 17 import org.springframework.beans.factory.annotation.Autowired;
@@ -34,6 +36,9 @@ public class SipLayer implements SipListener { @@ -34,6 +36,9 @@ public class SipLayer implements SipListener {
34 @Autowired 36 @Autowired
35 private SIPProcessorFactory processorFactory; 37 private SIPProcessorFactory processorFactory;
36 38
  39 + @Autowired
  40 + private SipSubscribe sipSubscribe;
  41 +
37 private SipStack sipStack; 42 private SipStack sipStack;
38 43
39 private SipFactory sipFactory; 44 private SipFactory sipFactory;
@@ -139,11 +144,19 @@ public class SipLayer implements SipListener { @@ -139,11 +144,19 @@ public class SipLayer implements SipListener {
139 // 增加其它无需回复的响应,如101、180等 144 // 增加其它无需回复的响应,如101、180等
140 } else { 145 } else {
141 logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/); 146 logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/);
  147 + if (evt.getResponse() != null && sipSubscribe.getSize() > 0 ) {
  148 + CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME);
  149 + if (callIdHeader != null) {
  150 + SipSubscribe.Event subscribe = sipSubscribe.getSubscribe(callIdHeader.getCallId());
  151 + if (subscribe != null) {
  152 + subscribe.response(evt);
  153 + }
  154 + }
  155 + }
142 } 156 }
143 - // trying不会回复  
144 - // if (status == Response.TRYING) {  
145 157
146 - // } 158 +
  159 +
147 } 160 }
148 161
149 /** 162 /**
src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java
@@ -21,6 +21,6 @@ public class RegisterLogicHandler { @@ -21,6 +21,6 @@ public class RegisterLogicHandler {
21 // TODO 后续处理,只有第一次注册时调用查询设备信息,如需更新调用更新API接口 21 // TODO 后续处理,只有第一次注册时调用查询设备信息,如需更新调用更新API接口
22 cmder.deviceInfoQuery(device); 22 cmder.deviceInfoQuery(device);
23 23
24 - cmder.catalogQuery(device); 24 + cmder.catalogQuery(device, null);
25 } 25 }
26 } 26 }
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.event;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
  5 +import org.slf4j.Logger;
  6 +import org.slf4j.LoggerFactory;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import javax.sip.ResponseEvent;
  10 +import javax.sip.message.Request;
  11 +import java.util.EventObject;
  12 +import java.util.Map;
  13 +import java.util.concurrent.ConcurrentHashMap;
  14 +
  15 +@Component
  16 +public class SipSubscribe {
  17 +
  18 + private final static Logger logger = LoggerFactory.getLogger(SipSubscribe.class);
  19 +
  20 + private Map<String, SipSubscribe.Event> allSubscribes = new ConcurrentHashMap<>();
  21 +
  22 + public interface Event {
  23 + void response(ResponseEvent event);
  24 + }
  25 +
  26 + public void addSubscribe(String key, SipSubscribe.Event event) {
  27 + allSubscribes.put(key, event);
  28 + }
  29 +
  30 + public SipSubscribe.Event getSubscribe(String key) {
  31 + return allSubscribes.get(key);
  32 + }
  33 +
  34 + public int getSize(){
  35 + return allSubscribes.size();
  36 + }
  37 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
@@ -4,10 +4,13 @@ import javax.sip.RequestEvent; @@ -4,10 +4,13 @@ import javax.sip.RequestEvent;
4 import javax.sip.ResponseEvent; 4 import javax.sip.ResponseEvent;
5 import javax.sip.SipProvider; 5 import javax.sip.SipProvider;
6 import javax.sip.header.CSeqHeader; 6 import javax.sip.header.CSeqHeader;
  7 +import javax.sip.header.CallIdHeader;
  8 +import javax.sip.header.Header;
7 import javax.sip.message.Request; 9 import javax.sip.message.Request;
8 import javax.sip.message.Response; 10 import javax.sip.message.Response;
9 11
10 import com.alibaba.fastjson.JSON; 12 import com.alibaba.fastjson.JSON;
  13 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
11 import org.slf4j.Logger; 14 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory; 15 import org.slf4j.LoggerFactory;
13 import org.springframework.beans.factory.annotation.Autowired; 16 import org.springframework.beans.factory.annotation.Autowired;
@@ -83,7 +86,8 @@ public class SIPProcessorFactory { @@ -83,7 +86,8 @@ public class SIPProcessorFactory {
83 86
84 @Autowired 87 @Autowired
85 private OtherResponseProcessor otherResponseProcessor; 88 private OtherResponseProcessor otherResponseProcessor;
86 - 89 +
  90 +
87 // 注:这里使用注解会导致循环依赖注入,暂用springBean 91 // 注:这里使用注解会导致循环依赖注入,暂用springBean
88 private SipProvider tcpSipProvider; 92 private SipProvider tcpSipProvider;
89 93
@@ -94,6 +98,7 @@ public class SIPProcessorFactory { @@ -94,6 +98,7 @@ public class SIPProcessorFactory {
94 Request request = evt.getRequest(); 98 Request request = evt.getRequest();
95 String method = request.getMethod(); 99 String method = request.getMethod();
96 // logger.info("接收到消息:"+request.getMethod()); 100 // logger.info("接收到消息:"+request.getMethod());
  101 +// sipSubscribe.getSubscribe(evt.getServerTransaction().getBranchId()).response(evt);
97 if (Request.INVITE.equals(method)) { 102 if (Request.INVITE.equals(method)) {
98 InviteRequestProcessor processor = new InviteRequestProcessor(); 103 InviteRequestProcessor processor = new InviteRequestProcessor();
99 processor.setRequestEvent(evt); 104 processor.setRequestEvent(evt);
@@ -145,6 +150,7 @@ public class SIPProcessorFactory { @@ -145,6 +150,7 @@ public class SIPProcessorFactory {
145 } 150 }
146 151
147 public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) { 152 public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) {
  153 +
148 Response response = evt.getResponse(); 154 Response response = evt.getResponse();
149 CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME); 155 CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
150 String method = cseqHeader.getMethod(); 156 String method = cseqHeader.getMethod();
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,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
2 2
3 import com.genersoft.iot.vmp.common.StreamInfo; 3 import com.genersoft.iot.vmp.common.StreamInfo;
4 import com.genersoft.iot.vmp.gb28181.bean.Device; 4 import com.genersoft.iot.vmp.gb28181.bean.Device;
  5 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
5 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; 6 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
6 7
7 /** 8 /**
@@ -83,7 +84,7 @@ public interface ISIPCommander { @@ -83,7 +84,7 @@ public interface ISIPCommander {
83 * @param device 视频设备 84 * @param device 视频设备
84 * @param channelId 预览通道 85 * @param channelId 预览通道
85 */ 86 */
86 - void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event); 87 + void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
87 88
88 /** 89 /**
89 * 请求回放视频流 90 * 请求回放视频流
@@ -93,7 +94,7 @@ public interface ISIPCommander { @@ -93,7 +94,7 @@ public interface ISIPCommander {
93 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss 94 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
94 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss 95 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
95 */ 96 */
96 - void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event); 97 + void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
97 98
98 /** 99 /**
99 * 视频流停止 100 * 视频流停止
@@ -175,7 +176,7 @@ public interface ISIPCommander { @@ -175,7 +176,7 @@ public interface ISIPCommander {
175 * 176 *
176 * @param device 视频设备 177 * @param device 视频设备
177 */ 178 */
178 - boolean catalogQuery(Device device); 179 + boolean catalogQuery(Device device, SipSubscribe.Event errorEvent);
179 180
180 /** 181 /**
181 * 查询录像信息 182 * 查询录像信息
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -4,22 +4,22 @@ import java.text.ParseException; @@ -4,22 +4,22 @@ import java.text.ParseException;
4 import java.util.regex.Matcher; 4 import java.util.regex.Matcher;
5 import java.util.regex.Pattern; 5 import java.util.regex.Pattern;
6 6
7 -import javax.sip.ClientTransaction;  
8 -import javax.sip.Dialog;  
9 -import javax.sip.InvalidArgumentException;  
10 -import javax.sip.SipException;  
11 -import javax.sip.SipProvider;  
12 -import javax.sip.TransactionDoesNotExistException; 7 +import javax.sip.*;
13 import javax.sip.address.SipURI; 8 import javax.sip.address.SipURI;
  9 +import javax.sip.header.CallIdHeader;
  10 +import javax.sip.header.Header;
14 import javax.sip.header.ViaHeader; 11 import javax.sip.header.ViaHeader;
15 import javax.sip.message.Request; 12 import javax.sip.message.Request;
16 13
17 import com.alibaba.fastjson.JSONObject; 14 import com.alibaba.fastjson.JSONObject;
18 import com.genersoft.iot.vmp.conf.MediaServerConfig; 15 import com.genersoft.iot.vmp.conf.MediaServerConfig;
19 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; 16 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  17 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
20 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; 18 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
21 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 19 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
22 import com.genersoft.iot.vmp.storager.IVideoManagerStorager; 20 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  21 +import org.slf4j.Logger;
  22 +import org.slf4j.LoggerFactory;
23 import org.springframework.beans.factory.annotation.Autowired; 23 import org.springframework.beans.factory.annotation.Autowired;
24 import org.springframework.beans.factory.annotation.Qualifier; 24 import org.springframework.beans.factory.annotation.Qualifier;
25 import org.springframework.beans.factory.annotation.Value; 25 import org.springframework.beans.factory.annotation.Value;
@@ -39,6 +39,8 @@ import com.genersoft.iot.vmp.gb28181.utils.DateUtil; @@ -39,6 +39,8 @@ import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
39 */ 39 */
40 @Component 40 @Component
41 public class SIPCommander implements ISIPCommander { 41 public class SIPCommander implements ISIPCommander {
  42 +
  43 + private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);
42 44
43 @Autowired 45 @Autowired
44 private SipConfig sipConfig; 46 private SipConfig sipConfig;
@@ -69,6 +71,9 @@ public class SIPCommander implements ISIPCommander { @@ -69,6 +71,9 @@ public class SIPCommander implements ISIPCommander {
69 @Autowired 71 @Autowired
70 private ZLMHttpHookSubscribe subscribe; 72 private ZLMHttpHookSubscribe subscribe;
71 73
  74 + @Autowired
  75 + private SipSubscribe sipSubscribe;
  76 +
72 77
73 78
74 /** 79 /**
@@ -221,7 +226,7 @@ public class SIPCommander implements ISIPCommander { @@ -221,7 +226,7 @@ public class SIPCommander implements ISIPCommander {
221 226
222 Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag"); 227 Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag");
223 228
224 - transmitRequest(device, request); 229 + transmitRequest(device, request, null);
225 return true; 230 return true;
226 } catch (SipException | ParseException | InvalidArgumentException e) { 231 } catch (SipException | ParseException | InvalidArgumentException e) {
227 e.printStackTrace(); 232 e.printStackTrace();
@@ -256,22 +261,23 @@ public class SIPCommander implements ISIPCommander { @@ -256,22 +261,23 @@ public class SIPCommander implements ISIPCommander {
256 ptzXml.append("</Control>\r\n"); 261 ptzXml.append("</Control>\r\n");
257 262
258 Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag"); 263 Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag");
259 -  
260 - transmitRequest(device, request); 264 + transmitRequest(device, request, null);
261 return true; 265 return true;
262 } catch (SipException | ParseException | InvalidArgumentException e) { 266 } catch (SipException | ParseException | InvalidArgumentException e) {
263 e.printStackTrace(); 267 e.printStackTrace();
264 } 268 }
265 return false; 269 return false;
266 } 270 }
  271 +
267 /** 272 /**
268 - * 请求预览视频流  
269 - * 273 + * 请求预览视频流
270 * @param device 视频设备 274 * @param device 视频设备
271 * @param channelId 预览通道 275 * @param channelId 预览通道
  276 + * @param event hook订阅
  277 + * @param errorEvent sip错误订阅
272 */ 278 */
273 @Override 279 @Override
274 - public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event) { 280 + public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
275 try { 281 try {
276 282
277 String ssrc = streamSession.createPlaySsrc(); 283 String ssrc = streamSession.createPlaySsrc();
@@ -300,7 +306,8 @@ public class SIPCommander implements ISIPCommander { @@ -300,7 +306,8 @@ public class SIPCommander implements ISIPCommander {
300 // 306 //
301 StringBuffer content = new StringBuffer(200); 307 StringBuffer content = new StringBuffer(200);
302 content.append("v=0\r\n"); 308 content.append("v=0\r\n");
303 - content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); 309 +// content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
  310 + content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
304 content.append("s=Play\r\n"); 311 content.append("s=Play\r\n");
305 content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); 312 content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n");
306 content.append("t=0 0\r\n"); 313 content.append("t=0 0\r\n");
@@ -332,7 +339,7 @@ public class SIPCommander implements ISIPCommander { @@ -332,7 +339,7 @@ public class SIPCommander implements ISIPCommander {
332 339
333 Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc); 340 Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc);
334 341
335 - ClientTransaction transaction = transmitRequest(device, request); 342 + ClientTransaction transaction = transmitRequest(device, request, errorEvent);
336 streamSession.put(streamId, transaction); 343 streamSession.put(streamId, transaction);
337 DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId); 344 DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
338 if (deviceChannel != null) { 345 if (deviceChannel != null) {
@@ -357,7 +364,8 @@ public class SIPCommander implements ISIPCommander { @@ -357,7 +364,8 @@ public class SIPCommander implements ISIPCommander {
357 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss 364 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
358 */ 365 */
359 @Override 366 @Override
360 - public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event) { 367 + public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
  368 + , SipSubscribe.Event errorEvent) {
361 try { 369 try {
362 MediaServerConfig mediaInfo = storager.getMediaInfo(); 370 MediaServerConfig mediaInfo = storager.getMediaInfo();
363 String ssrc = streamSession.createPlayBackSsrc(); 371 String ssrc = streamSession.createPlayBackSsrc();
@@ -413,8 +421,8 @@ public class SIPCommander implements ISIPCommander { @@ -413,8 +421,8 @@ public class SIPCommander implements ISIPCommander {
413 content.append("y="+ssrc+"\r\n");//ssrc 421 content.append("y="+ssrc+"\r\n");//ssrc
414 422
415 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null); 423 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null);
416 -  
417 - ClientTransaction transaction = transmitRequest(device, request); 424 +
  425 + ClientTransaction transaction = transmitRequest(device, request, errorEvent);
418 streamSession.put(streamId, transaction); 426 streamSession.put(streamId, transaction);
419 427
420 } catch ( SipException | ParseException | InvalidArgumentException e) { 428 } catch ( SipException | ParseException | InvalidArgumentException e) {
@@ -575,7 +583,8 @@ public class SIPCommander implements ISIPCommander { @@ -575,7 +583,8 @@ public class SIPCommander implements ISIPCommander {
575 catalogXml.append("</Query>\r\n"); 583 catalogXml.append("</Query>\r\n");
576 584
577 Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaDeviceInfoBranch", "FromDeviceInfoTag", "ToDeviceInfoTag"); 585 Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaDeviceInfoBranch", "FromDeviceInfoTag", "ToDeviceInfoTag");
578 - transmitRequest(device, request); 586 +
  587 + transmitRequest(device, request, null);
579 588
580 } catch (SipException | ParseException | InvalidArgumentException e) { 589 } catch (SipException | ParseException | InvalidArgumentException e) {
581 e.printStackTrace(); 590 e.printStackTrace();
@@ -590,7 +599,7 @@ public class SIPCommander implements ISIPCommander { @@ -590,7 +599,7 @@ public class SIPCommander implements ISIPCommander {
590 * @param device 视频设备 599 * @param device 视频设备
591 */ 600 */
592 @Override 601 @Override
593 - public boolean catalogQuery(Device device) { 602 + public boolean catalogQuery(Device device, SipSubscribe.Event errorEvent) {
594 // 清空通道 603 // 清空通道
595 storager.cleanChannelsForDevice(device.getDeviceId()); 604 storager.cleanChannelsForDevice(device.getDeviceId());
596 try { 605 try {
@@ -602,8 +611,9 @@ public class SIPCommander implements ISIPCommander { @@ -602,8 +611,9 @@ public class SIPCommander implements ISIPCommander {
602 catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); 611 catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
603 catalogXml.append("</Query>\r\n"); 612 catalogXml.append("</Query>\r\n");
604 613
605 - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaCatalogBranch", "FromCatalogTag", "ToCatalogTag");  
606 - transmitRequest(device, request); 614 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaCatalogBranch", "FromCatalogTag", null);
  615 +
  616 + transmitRequest(device, request, errorEvent);
607 } catch (SipException | ParseException | InvalidArgumentException e) { 617 } catch (SipException | ParseException | InvalidArgumentException e) {
608 e.printStackTrace(); 618 e.printStackTrace();
609 return false; 619 return false;
@@ -636,7 +646,9 @@ public class SIPCommander implements ISIPCommander { @@ -636,7 +646,9 @@ public class SIPCommander implements ISIPCommander {
636 recordInfoXml.append("</Query>\r\n"); 646 recordInfoXml.append("</Query>\r\n");
637 647
638 Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", "ToRecordInfoTag"); 648 Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", "ToRecordInfoTag");
639 - transmitRequest(device, request); 649 +
  650 +
  651 + transmitRequest(device, request, null);
640 } catch (SipException | ParseException | InvalidArgumentException e) { 652 } catch (SipException | ParseException | InvalidArgumentException e) {
641 e.printStackTrace(); 653 e.printStackTrace();
642 return false; 654 return false;
@@ -688,13 +700,20 @@ public class SIPCommander implements ISIPCommander { @@ -688,13 +700,20 @@ public class SIPCommander implements ISIPCommander {
688 return false; 700 return false;
689 } 701 }
690 702
691 - private ClientTransaction transmitRequest(Device device, Request request) throws SipException { 703 + private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent) throws SipException {
692 ClientTransaction clientTransaction = null; 704 ClientTransaction clientTransaction = null;
693 if("TCP".equals(device.getTransport())) { 705 if("TCP".equals(device.getTransport())) {
694 clientTransaction = tcpSipProvider.getNewClientTransaction(request); 706 clientTransaction = tcpSipProvider.getNewClientTransaction(request);
695 } else if("UDP".equals(device.getTransport())) { 707 } else if("UDP".equals(device.getTransport())) {
696 clientTransaction = udpSipProvider.getNewClientTransaction(request); 708 clientTransaction = udpSipProvider.getNewClientTransaction(request);
697 } 709 }
  710 +
  711 + // 添加订阅
  712 + if (errorEvent != null) {
  713 + CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
  714 + sipSubscribe.addSubscribe(callIdHeader.getCallId(), errorEvent);
  715 + }
  716 +
698 clientTransaction.sendRequest(); 717 clientTransaction.sendRequest();
699 return clientTransaction; 718 return clientTransaction;
700 } 719 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
@@ -294,7 +294,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { @@ -294,7 +294,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
294 device.setStreamMode("UDP"); 294 device.setStreamMode("UDP");
295 } 295 }
296 storager.updateDevice(device); 296 storager.updateDevice(device);
297 - cmder.catalogQuery(device); 297 + cmder.catalogQuery(device, null);
298 // 回复200 OK 298 // 回复200 OK
299 responseAck(evt); 299 responseAck(evt);
300 if (offLineDetector.isOnline(deviceId)) { 300 if (offLineDetector.isOnline(deviceId)) {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -323,7 +323,7 @@ public class ZLMHttpHookListener { @@ -323,7 +323,7 @@ public class ZLMHttpHookListener {
323 cmder.playStreamCmd(device, channelId, (JSONObject response) -> { 323 cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
324 logger.info("收到订阅消息: " + response.toJSONString()); 324 logger.info("收到订阅消息: " + response.toJSONString());
325 playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); 325 playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
326 - }); 326 + }, null);
327 } 327 }
328 328
329 } 329 }
src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java
@@ -34,6 +34,7 @@ public class SpringBeanFactory implements ApplicationContextAware { @@ -34,6 +34,7 @@ public class SpringBeanFactory implements ApplicationContextAware {
34 * 获取对象 这里重写了bean方法,起主要作用 34 * 获取对象 这里重写了bean方法,起主要作用
35 */ 35 */
36 public static Object getBean(String beanId) throws BeansException { 36 public static Object getBean(String beanId) throws BeansException {
  37 + if (applicationContext == null) return null;
37 return applicationContext.getBean(beanId); 38 return applicationContext.getBean(beanId);
38 } 39 }
39 40
src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java
@@ -4,6 +4,7 @@ import java.util.List; @@ -4,6 +4,7 @@ import java.util.List;
4 4
5 import com.genersoft.iot.vmp.common.PageResult; 5 import com.genersoft.iot.vmp.common.PageResult;
6 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; 6 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  7 +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
7 import org.slf4j.Logger; 8 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory; 9 import org.slf4j.LoggerFactory;
9 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.beans.factory.annotation.Autowired;
@@ -19,6 +20,8 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; @@ -19,6 +20,8 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
19 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 20 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
20 import com.genersoft.iot.vmp.storager.IVideoManagerStorager; 21 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
21 22
  23 +import javax.sip.message.Response;
  24 +
22 @CrossOrigin 25 @CrossOrigin
23 @RestController 26 @RestController
24 @RequestMapping("/api") 27 @RequestMapping("/api")
@@ -86,11 +89,25 @@ public class DeviceController { @@ -86,11 +89,25 @@ public class DeviceController {
86 89
87 if (logger.isDebugEnabled()) { 90 if (logger.isDebugEnabled()) {
88 } 91 }
89 - logger.debug("设备信息同步API调用,deviceId:" + deviceId); 92 + logger.debug("设备通道信息同步API调用,deviceId:" + deviceId);
90 93
91 Device device = storager.queryVideoDevice(deviceId); 94 Device device = storager.queryVideoDevice(deviceId);
92 - cmder.catalogQuery(device);  
93 - DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(); 95 + cmder.catalogQuery(device, event -> {
  96 + Response response = event.getResponse();
  97 + RequestMessage msg = new RequestMessage();
  98 + msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId);
  99 + msg.setData(String.format("同步通道失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
  100 + resultHolder.invokeResult(msg);
  101 + });
  102 + DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(2*1000L);
  103 + result.onTimeout(()->{
  104 + logger.warn(String.format("设备通道信息同步超时"));
  105 + // 释放rtpserver
  106 + RequestMessage msg = new RequestMessage();
  107 + msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId);
  108 + msg.setData("Timeout");
  109 + resultHolder.invokeResult(msg);
  110 + });
94 resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result); 111 resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result);
95 return result; 112 return result;
96 } 113 }
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
@@ -28,6 +28,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; @@ -28,6 +28,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
28 import com.genersoft.iot.vmp.storager.IVideoManagerStorager; 28 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
29 import org.springframework.web.context.request.async.DeferredResult; 29 import org.springframework.web.context.request.async.DeferredResult;
30 30
  31 +import javax.sip.message.Response;
31 import java.text.DecimalFormat; 32 import java.text.DecimalFormat;
32 import java.util.UUID; 33 import java.util.UUID;
33 34
@@ -72,6 +73,12 @@ public class PlayController { @@ -72,6 +73,12 @@ public class PlayController {
72 cmder.playStreamCmd(device, channelId, (JSONObject response) -> { 73 cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
73 logger.info("收到订阅消息: " + response.toJSONString()); 74 logger.info("收到订阅消息: " + response.toJSONString());
74 playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); 75 playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
  76 + }, event -> {
  77 + RequestMessage msg = new RequestMessage();
  78 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  79 + Response response = event.getResponse();
  80 + msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
  81 + resultHolder.invokeResult(msg);
75 }); 82 });
76 } else { 83 } else {
77 String streamId = streamInfo.getStreamId(); 84 String streamId = streamInfo.getStreamId();
@@ -86,6 +93,12 @@ public class PlayController { @@ -86,6 +93,12 @@ public class PlayController {
86 cmder.playStreamCmd(device, channelId, (JSONObject response) -> { 93 cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
87 logger.info("收到订阅消息: " + response.toJSONString()); 94 logger.info("收到订阅消息: " + response.toJSONString());
88 playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); 95 playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
  96 + }, event -> {
  97 + RequestMessage msg = new RequestMessage();
  98 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  99 + Response response = event.getResponse();
  100 + msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
  101 + resultHolder.invokeResult(msg);
89 }); 102 });
90 } 103 }
91 } 104 }
src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
@@ -27,6 +27,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; @@ -27,6 +27,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
27 import com.genersoft.iot.vmp.storager.IVideoManagerStorager; 27 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
28 import org.springframework.web.context.request.async.DeferredResult; 28 import org.springframework.web.context.request.async.DeferredResult;
29 29
  30 +import javax.sip.message.Response;
30 import java.util.UUID; 31 import java.util.UUID;
31 32
32 @CrossOrigin 33 @CrossOrigin
@@ -78,6 +79,12 @@ public class PlaybackController { @@ -78,6 +79,12 @@ public class PlaybackController {
78 cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> { 79 cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> {
79 logger.info("收到订阅消息: " + response.toJSONString()); 80 logger.info("收到订阅消息: " + response.toJSONString());
80 playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString()); 81 playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString());
  82 + }, event -> {
  83 + Response response = event.getResponse();
  84 + RequestMessage msg = new RequestMessage();
  85 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  86 + msg.setData(String.format("回放失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
  87 + resultHolder.invokeResult(msg);
81 }); 88 });
82 89
83 return result; 90 return result;
web_src/src/components/videoList.vue
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
8 <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> 8 <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
9 <span style="font-size: 1rem; font-weight: bold;">设备列表</span> 9 <span style="font-size: 1rem; font-weight: bold;">设备列表</span>
10 <div style="position: absolute; right: 1rem; top: 0.3rem;"> 10 <div style="position: absolute; right: 1rem; top: 0.3rem;">
11 - <el-button icon="el-icon-refresh-right" circle size="mini" @click="getDeviceList()"></el-button> 11 + <el-button icon="el-icon-refresh-right" circle size="mini" :loading="getDeviceListLoading" @click="getDeviceList()"></el-button>
12 </div> 12 </div>
13 </div> 13 </div>
14 <devicePlayer ref="devicePlayer"></devicePlayer> 14 <devicePlayer ref="devicePlayer"></devicePlayer>
@@ -51,7 +51,7 @@ @@ -51,7 +51,7 @@
51 51
52 <el-table-column label="操作" width="240" align="center" fixed="right"> 52 <el-table-column label="操作" width="240" align="center" fixed="right">
53 <template slot-scope="scope"> 53 <template slot-scope="scope">
54 - <el-button size="mini" icon="el-icon-refresh" @click="refDevice(scope.row)">刷新通道</el-button> 54 + <el-button size="mini" :ref="scope.row.deviceId + 'refbtn' " icon="el-icon-refresh" @click="refDevice(scope.row)">刷新通道</el-button>
55 <el-button size="mini" icon="el-icon-s-open" type="primary" @click="showChannelList(scope.row)">查看通道</el-button> 55 <el-button size="mini" icon="el-icon-s-open" type="primary" @click="showChannelList(scope.row)">查看通道</el-button>
56 </template> 56 </template>
57 </el-table-column> 57 </el-table-column>
@@ -90,7 +90,8 @@ @@ -90,7 +90,8 @@
90 winHeight: window.innerHeight - 200, 90 winHeight: window.innerHeight - 200,
91 currentPage:1, 91 currentPage:1,
92 count:15, 92 count:15,
93 - total:0 93 + total:0,
  94 + getDeviceListLoading: false
94 }; 95 };
95 }, 96 },
96 computed: { 97 computed: {
@@ -130,7 +131,7 @@ @@ -130,7 +131,7 @@
130 }, 131 },
131 getDeviceList: function() { 132 getDeviceList: function() {
132 let that = this; 133 let that = this;
133 - 134 + this.getDeviceListLoading = true;
134 this.$axios.get(`/api/devices`,{ 135 this.$axios.get(`/api/devices`,{
135 params: { 136 params: {
136 page: that.currentPage - 1, 137 page: that.currentPage - 1,
@@ -141,9 +142,11 @@ @@ -141,9 +142,11 @@
141 console.log(res); 142 console.log(res);
142 that.total = res.data.total; 143 that.total = res.data.total;
143 that.deviceList = res.data.data; 144 that.deviceList = res.data.data;
  145 + that.getDeviceListLoading = false;
144 }) 146 })
145 .catch(function (error) { 147 .catch(function (error) {
146 console.log(error); 148 console.log(error);
  149 + that.getDeviceListLoading = false;
147 }); 150 });
148 151
149 }, 152 },
@@ -158,17 +161,30 @@ @@ -158,17 +161,30 @@
158 refDevice: function(itemData) { 161 refDevice: function(itemData) {
159 ///api/devices/{deviceId}/sync 162 ///api/devices/{deviceId}/sync
160 console.log("刷新对应设备:" + itemData.deviceId); 163 console.log("刷新对应设备:" + itemData.deviceId);
  164 + var that = this;
  165 + that.$refs[itemData.deviceId + 'refbtn' ].loading = true;
161 this.$axios({ 166 this.$axios({
162 method: 'post', 167 method: 'post',
163 url: '/api/devices/' + itemData.deviceId + '/sync' 168 url: '/api/devices/' + itemData.deviceId + '/sync'
164 }).then(function(res) { 169 }).then(function(res) {
165 - // console.log("刷新设备结果:"+JSON.stringify(res)); 170 + console.log("刷新设备结果:"+JSON.stringify(res));
  171 + if (!res.data.deviceId) {
  172 + that.$message({
  173 + showClose: true,
  174 + message: res.data,
  175 + type: 'error'
  176 + });
  177 + }else{
  178 + that.$message({
  179 + showClose: true,
  180 + message: '请求成功',
  181 + type: 'success'
  182 + });
  183 + }
  184 + that.$refs[itemData.deviceId + 'refbtn' ].loading = false;
166 }).catch(function(e) { 185 }).catch(function(e) {
167 - that.$message({  
168 - showClose: true,  
169 - message: '请求成功',  
170 - type: 'success'  
171 - }); 186 + console.error(e)
  187 + that.$refs[itemData.deviceId + 'refbtn' ].loading = false;
172 });; 188 });;
173 }, 189 },
174 //通知设备上传媒体流 190 //通知设备上传媒体流