Commit 3a502b36a8cfcdd455edb22e5771115559873731

Authored by songww
1 parent 2e778e34

完善ssrc符合国标,并完善很多小问题

src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
@@ -3,7 +3,7 @@ package com.genersoft.iot.vmp.conf; @@ -3,7 +3,7 @@ package com.genersoft.iot.vmp.conf;
3 import org.springframework.beans.factory.annotation.Value; 3 import org.springframework.beans.factory.annotation.Value;
4 import org.springframework.context.annotation.Configuration; 4 import org.springframework.context.annotation.Configuration;
5 5
6 -@Configuration 6 +@Configuration("sipConfig")
7 public class SipConfig { 7 public class SipConfig {
8 8
9 @Value("${sip.ip}") 9 @Value("${sip.ip}")
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -42,7 +42,7 @@ public class SipLayer implements SipListener, Runnable { @@ -42,7 +42,7 @@ public class SipLayer implements SipListener, Runnable {
42 private final static Logger logger = LoggerFactory.getLogger(SipLayer.class); 42 private final static Logger logger = LoggerFactory.getLogger(SipLayer.class);
43 43
44 @Autowired 44 @Autowired
45 - private SipConfig config; 45 + private SipConfig sipConfig;
46 46
47 private SipProvider tcpSipProvider; 47 private SipProvider tcpSipProvider;
48 48
@@ -77,7 +77,7 @@ public class SipLayer implements SipListener, Runnable { @@ -77,7 +77,7 @@ public class SipLayer implements SipListener, Runnable {
77 77
78 Properties properties = new Properties(); 78 Properties properties = new Properties();
79 properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); 79 properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP");
80 - properties.setProperty("javax.sip.IP_ADDRESS", config.getSipIp()); 80 + properties.setProperty("javax.sip.IP_ADDRESS", sipConfig.getSipIp());
81 properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "false"); 81 properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "false");
82 /** 82 /**
83 * sip_server_log.log 和 sip_debug_log.log public static final int TRACE_NONE = 83 * sip_server_log.log 和 sip_debug_log.log public static final int TRACE_NONE =
@@ -92,20 +92,20 @@ public class SipLayer implements SipListener, Runnable { @@ -92,20 +92,20 @@ public class SipLayer implements SipListener, Runnable {
92 startTcpListener(); 92 startTcpListener();
93 startUdpListener(); 93 startUdpListener();
94 } catch (Exception e) { 94 } catch (Exception e) {
95 - logger.error("Sip Server 启动失败! port {" + config.getSipPort() + "}"); 95 + logger.error("Sip Server 启动失败! port {" + sipConfig.getSipPort() + "}");
96 e.printStackTrace(); 96 e.printStackTrace();
97 } 97 }
98 - logger.info("Sip Server 启动成功 port {" + config.getSipPort() + "}"); 98 + logger.info("Sip Server 启动成功 port {" + sipConfig.getSipPort() + "}");
99 } 99 }
100 100
101 private void startTcpListener() throws Exception { 101 private void startTcpListener() throws Exception {
102 - ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(config.getSipIp(), config.getSipPort(), "TCP"); 102 + ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getSipIp(), sipConfig.getSipPort(), "TCP");
103 tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint); 103 tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint);
104 tcpSipProvider.addSipListener(this); 104 tcpSipProvider.addSipListener(this);
105 } 105 }
106 106
107 private void startUdpListener() throws Exception { 107 private void startUdpListener() throws Exception {
108 - ListeningPoint udpListeningPoint = sipStack.createListeningPoint(config.getSipIp(), config.getSipPort(), "UDP"); 108 + ListeningPoint udpListeningPoint = sipStack.createListeningPoint(sipConfig.getSipIp(), sipConfig.getSipPort(), "UDP");
109 udpSipProvider = sipStack.createSipProvider(udpListeningPoint); 109 udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
110 udpSipProvider.addSipListener(this); 110 udpSipProvider.addSipListener(this);
111 } 111 }
@@ -126,7 +126,7 @@ public class SipLayer implements SipListener, Runnable { @@ -126,7 +126,7 @@ public class SipLayer implements SipListener, Runnable {
126 int status = response.getStatusCode(); 126 int status = response.getStatusCode();
127 if ((status >= 200) && (status < 300)) { // Success! 127 if ((status >= 200) && (status < 300)) { // Success!
128 ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt); 128 ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
129 - processor.process(evt, this, config); 129 + processor.process(evt, this, sipConfig);
130 } else { 130 } else {
131 logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getContent().toString()); 131 logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getContent().toString());
132 } 132 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java
@@ -23,7 +23,7 @@ public class RecordItem { @@ -23,7 +23,7 @@ public class RecordItem {
23 23
24 private String type; 24 private String type;
25 25
26 - private String recordId; 26 + private String recorderId;
27 27
28 public String getDeviceId() { 28 public String getDeviceId() {
29 return deviceId; 29 return deviceId;
@@ -81,12 +81,12 @@ public class RecordItem { @@ -81,12 +81,12 @@ public class RecordItem {
81 this.type = type; 81 this.type = type;
82 } 82 }
83 83
84 - public String getRecordId() {  
85 - return recordId; 84 + public String getRecorderId() {
  85 + return recorderId;
86 } 86 }
87 87
88 - public void setRecordId(String recordId) {  
89 - this.recordId = recordId; 88 + public void setRecordId(String recorderId) {
  89 + this.recorderId = recorderId;
90 } 90 }
91 91
92 public String getEndTime() { 92 public String getEndTime() {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -72,6 +72,16 @@ public interface ISIPCommander { @@ -72,6 +72,16 @@ public interface ISIPCommander {
72 public String playStreamCmd(Device device,String channelId); 72 public String playStreamCmd(Device device,String channelId);
73 73
74 /** 74 /**
  75 + * 请求回放视频流
  76 + *
  77 + * @param device 视频设备
  78 + * @param channelId 预览通道
  79 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  80 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  81 + */
  82 + public String playbackStreamCmd(Device device,String channelId, String recordId, String startTime, String endTime);
  83 +
  84 + /**
75 * 语音广播 85 * 语音广播
76 * 86 *
77 * @param device 视频设备 87 * @param device 视频设备
@@ -153,7 +163,7 @@ public interface ISIPCommander { @@ -153,7 +163,7 @@ public interface ISIPCommander {
153 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss 163 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
154 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss 164 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
155 */ 165 */
156 - public boolean recordInfoQuery(Device device, String startTime, String endTime); 166 + public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime);
157 167
158 /** 168 /**
159 * 查询报警信息 169 * 查询报警信息
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
@@ -35,7 +35,7 @@ public class SIPRequestHeaderProvider { @@ -35,7 +35,7 @@ public class SIPRequestHeaderProvider {
35 private SipLayer layer; 35 private SipLayer layer;
36 36
37 @Autowired 37 @Autowired
38 - private SipConfig config; 38 + private SipConfig sipConfig;
39 39
40 public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException { 40 public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException {
41 Request request = null; 41 Request request = null;
@@ -44,12 +44,12 @@ public class SIPRequestHeaderProvider { @@ -44,12 +44,12 @@ public class SIPRequestHeaderProvider {
44 SipURI requestURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); 44 SipURI requestURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
45 // via 45 // via
46 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 46 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
47 - ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(config.getSipIp(), config.getSipPort(), 47 + ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(),
48 device.getTransport(), viaTag); 48 device.getTransport(), viaTag);
49 viaHeaders.add(viaHeader); 49 viaHeaders.add(viaHeader);
50 // from 50 // from
51 SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), 51 SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),
52 - config.getSipIp() + ":" + config.getSipPort()); 52 + sipConfig.getSipIp() + ":" + sipConfig.getSipPort());
53 Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI); 53 Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI);
54 FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); 54 FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag);
55 // to 55 // to
@@ -78,11 +78,11 @@ public class SIPRequestHeaderProvider { @@ -78,11 +78,11 @@ public class SIPRequestHeaderProvider {
78 SipURI requestLine = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); 78 SipURI requestLine = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
79 //via 79 //via
80 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 80 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
81 - ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(config.getSipIp(), config.getSipPort(), device.getTransport(), viaTag); 81 + ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag);
82 viaHeader.setRPort(); 82 viaHeader.setRPort();
83 viaHeaders.add(viaHeader); 83 viaHeaders.add(viaHeader);
84 //from 84 //from
85 - SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),config.getSipIp()+":"+config.getSipPort()); 85 + SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),sipConfig.getSipIp()+":"+sipConfig.getSipPort());
86 Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI); 86 Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI);
87 FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack 87 FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
88 //to 88 //to
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -17,6 +17,9 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; @@ -17,6 +17,9 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
17 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; 17 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
18 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; 18 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
19 import com.genersoft.iot.vmp.gb28181.utils.DateUtil; 19 import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
  20 +import com.genersoft.iot.vmp.gb28181.utils.SsrcUtil;
  21 +
  22 +import tk.mybatis.mapper.util.StringUtil;
20 23
21 /** 24 /**
22 * @Description:设备能力接口,用于定义设备的控制、查询能力 25 * @Description:设备能力接口,用于定义设备的控制、查询能力
@@ -27,7 +30,7 @@ import com.genersoft.iot.vmp.gb28181.utils.DateUtil; @@ -27,7 +30,7 @@ import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
27 public class SIPCommander implements ISIPCommander { 30 public class SIPCommander implements ISIPCommander {
28 31
29 @Autowired 32 @Autowired
30 - private SipConfig config; 33 + private SipConfig sipConfig;
31 34
32 @Autowired 35 @Autowired
33 private SIPRequestHeaderProvider headerProvider; 36 private SIPRequestHeaderProvider headerProvider;
@@ -46,7 +49,7 @@ public class SIPCommander implements ISIPCommander { @@ -46,7 +49,7 @@ public class SIPCommander implements ISIPCommander {
46 */ 49 */
47 @Override 50 @Override
48 public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) { 51 public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) {
49 - return ptzCmd(device, channelId, leftRight, upDown, 0, config.getSpeed(), 0); 52 + return ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getSpeed(), 0);
50 } 53 }
51 54
52 /** 55 /**
@@ -72,7 +75,7 @@ public class SIPCommander implements ISIPCommander { @@ -72,7 +75,7 @@ public class SIPCommander implements ISIPCommander {
72 */ 75 */
73 @Override 76 @Override
74 public boolean ptzZoomCmd(Device device, String channelId, int inOut) { 77 public boolean ptzZoomCmd(Device device, String channelId, int inOut) {
75 - return ptzCmd(device, channelId, 0, 0, inOut, 0, config.getSpeed()); 78 + return ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getSpeed());
76 } 79 }
77 80
78 /** 81 /**
@@ -135,23 +138,19 @@ public class SIPCommander implements ISIPCommander { @@ -135,23 +138,19 @@ public class SIPCommander implements ISIPCommander {
135 public String playStreamCmd(Device device, String channelId) { 138 public String playStreamCmd(Device device, String channelId) {
136 try { 139 try {
137 140
138 - //生成ssrc标识数据流 10位数字  
139 - String ssrc = "";  
140 - Random random = new Random();  
141 - // ZLMediaServer最大识别7FFFFFFF即2147483647,所以随机数不能超过这个数  
142 - ssrc = String.valueOf(random.nextInt(2147483647)); 141 + String ssrc = SsrcUtil.getPlaySsrc();
143 // 142 //
144 StringBuffer content = new StringBuffer(200); 143 StringBuffer content = new StringBuffer(200);
145 content.append("v=0\r\n"); 144 content.append("v=0\r\n");
146 - content.append("o="+channelId+" 0 0 IN IP4 "+config.getSipIp()+"\r\n"); 145 + content.append("o="+channelId+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n");
147 content.append("s=Play\r\n"); 146 content.append("s=Play\r\n");
148 - content.append("c=IN IP4 "+config.getMediaIp()+"\r\n"); 147 + content.append("c=IN IP4 "+sipConfig.getMediaIp()+"\r\n");
149 content.append("t=0 0\r\n"); 148 content.append("t=0 0\r\n");
150 if(device.getTransport().equals("TCP")) { 149 if(device.getTransport().equals("TCP")) {
151 - content.append("m=video "+config.getMediaPort()+" TCP/RTP/AVP 96 98 97\r\n"); 150 + content.append("m=video "+sipConfig.getMediaPort()+" TCP/RTP/AVP 96 98 97\r\n");
152 } 151 }
153 if(device.getTransport().equals("UDP")) { 152 if(device.getTransport().equals("UDP")) {
154 - content.append("m=video "+config.getMediaPort()+" RTP/AVP 96 98 97\r\n"); 153 + content.append("m=video "+sipConfig.getMediaPort()+" RTP/AVP 96 98 97\r\n");
155 } 154 }
156 content.append("a=sendrecv\r\n"); 155 content.append("a=sendrecv\r\n");
157 content.append("a=rtpmap:96 PS/90000\r\n"); 156 content.append("a=rtpmap:96 PS/90000\r\n");
@@ -172,6 +171,53 @@ public class SIPCommander implements ISIPCommander { @@ -172,6 +171,53 @@ public class SIPCommander implements ISIPCommander {
172 return null; 171 return null;
173 } 172 }
174 } 173 }
  174 +
  175 + /**
  176 + * 请求回放视频流
  177 + *
  178 + * @param device 视频设备
  179 + * @param channelId 预览通道
  180 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  181 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  182 + */
  183 + @Override
  184 + public String playbackStreamCmd(Device device, String channelId, String recordId, String startTime, String endTime) {
  185 + try {
  186 +
  187 + String ssrc = SsrcUtil.getPlayBackSsrc();
  188 + //
  189 + StringBuffer content = new StringBuffer(200);
  190 + content.append("v=0\r\n");
  191 + content.append("o="+channelId+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n");
  192 + content.append("s=Playback\r\n");
  193 + content.append("u="+recordId+":3\r\n");
  194 + content.append("c=IN IP4 "+sipConfig.getMediaIp()+"\r\n");
  195 + content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
  196 + if(device.getTransport().equals("TCP")) {
  197 + content.append("m=video "+sipConfig.getMediaPort()+" TCP/RTP/AVP 96 98 97\r\n");
  198 + }
  199 + if(device.getTransport().equals("UDP")) {
  200 + content.append("m=video "+sipConfig.getMediaPort()+" RTP/AVP 96 98 97\r\n");
  201 + }
  202 + content.append("a=recvonly\r\n");
  203 + content.append("a=rtpmap:96 PS/90000\r\n");
  204 + content.append("a=rtpmap:98 H264/90000\r\n");
  205 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  206 + if(device.getTransport().equals("TCP")){
  207 + content.append("a=setup:passive\r\n");
  208 + content.append("a=connection:new\r\n");
  209 + }
  210 + content.append("y="+ssrc+"\r\n");//ssrc
  211 +
  212 + Request request = headerProvider.createInviteRequest(device, content.toString(), null, "live", null);
  213 +
  214 + transmitRequest(device, request);
  215 + return ssrc;
  216 + } catch ( SipException | ParseException | InvalidArgumentException e) {
  217 + e.printStackTrace();
  218 + return null;
  219 + }
  220 + }
175 221
176 /** 222 /**
177 * 语音广播 223 * 语音广播
@@ -323,22 +369,23 @@ public class SIPCommander implements ISIPCommander { @@ -323,22 +369,23 @@ public class SIPCommander implements ISIPCommander {
323 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss 369 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
324 */ 370 */
325 @Override 371 @Override
326 - public boolean recordInfoQuery(Device device, String startTime, String endTime) { 372 + public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime) {
327 373
328 try { 374 try {
329 - StringBuffer catalogXml = new StringBuffer(200);  
330 - catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>");  
331 - catalogXml.append("<Query>");  
332 - catalogXml.append("<CmdType>RecordInfo</CmdType>");  
333 - catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>");  
334 - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>");  
335 - catalogXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>");  
336 - catalogXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>"); 375 + StringBuffer recordInfoXml = new StringBuffer(200);
  376 + recordInfoXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>");
  377 + recordInfoXml.append("<Query>");
  378 + recordInfoXml.append("<CmdType>RecordInfo</CmdType>");
  379 + recordInfoXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>");
  380 + recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>");
  381 + recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>");
  382 + recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>");
  383 + recordInfoXml.append("<Secrecy>0</Secrecy>");
337 // 大华NVR要求必须增加一个值为all的文本元素节点Type 384 // 大华NVR要求必须增加一个值为all的文本元素节点Type
338 - catalogXml.append("<Type>all</Type>");  
339 - catalogXml.append("</Query>"); 385 + recordInfoXml.append("<Type>all</Type>");
  386 + recordInfoXml.append("</Query>");
340 387
341 - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", "ToRecordInfoTag"); 388 + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", "ToRecordInfoTag");
342 transmitRequest(device, request); 389 transmitRequest(device, request);
343 } catch (SipException | ParseException | InvalidArgumentException e) { 390 } catch (SipException | ParseException | InvalidArgumentException e) {
344 e.printStackTrace(); 391 e.printStackTrace();
@@ -398,4 +445,5 @@ public class SIPCommander implements ISIPCommander { @@ -398,4 +445,5 @@ public class SIPCommander implements ISIPCommander {
398 sipLayer.getUdpSipProvider().sendRequest(request); 445 sipLayer.getUdpSipProvider().sendRequest(request);
399 } 446 }
400 } 447 }
  448 +
401 } 449 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
@@ -19,6 +19,8 @@ import org.dom4j.Document; @@ -19,6 +19,8 @@ import org.dom4j.Document;
19 import org.dom4j.DocumentException; 19 import org.dom4j.DocumentException;
20 import org.dom4j.Element; 20 import org.dom4j.Element;
21 import org.dom4j.io.SAXReader; 21 import org.dom4j.io.SAXReader;
  22 +import org.slf4j.Logger;
  23 +import org.slf4j.LoggerFactory;
22 import org.springframework.beans.factory.annotation.Autowired; 24 import org.springframework.beans.factory.annotation.Autowired;
23 import org.springframework.stereotype.Component; 25 import org.springframework.stereotype.Component;
24 26
@@ -36,6 +38,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor; @@ -36,6 +38,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
36 import com.genersoft.iot.vmp.gb28181.utils.DateUtil; 38 import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
37 import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; 39 import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
38 import com.genersoft.iot.vmp.storager.IVideoManagerStorager; 40 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  41 +import com.genersoft.iot.vmp.utils.redis.RedisUtil;
39 42
40 /** 43 /**
41 * @Description:MESSAGE请求处理器 44 * @Description:MESSAGE请求处理器
@@ -44,7 +47,9 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager; @@ -44,7 +47,9 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
44 */ 47 */
45 @Component 48 @Component
46 public class MessageRequestProcessor implements ISIPRequestProcessor { 49 public class MessageRequestProcessor implements ISIPRequestProcessor {
47 - 50 +
  51 + private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class);
  52 +
48 private ServerTransaction transaction; 53 private ServerTransaction transaction;
49 54
50 private SipLayer layer; 55 private SipLayer layer;
@@ -59,8 +64,13 @@ public class MessageRequestProcessor implements ISIPRequestProcessor { @@ -59,8 +64,13 @@ public class MessageRequestProcessor implements ISIPRequestProcessor {
59 private EventPublisher publisher; 64 private EventPublisher publisher;
60 65
61 @Autowired 66 @Autowired
  67 + private RedisUtil redis;
  68 +
  69 + @Autowired
62 private DeferredResultHolder deferredResultHolder; 70 private DeferredResultHolder deferredResultHolder;
63 71
  72 + private final static String CACHE_RECORDINFO_KEY = "CACHE_RECORDINFO_";
  73 +
64 /** 74 /**
65 * 处理MESSAGE请求 75 * 处理MESSAGE请求
66 * 76 *
@@ -77,14 +87,19 @@ public class MessageRequestProcessor implements ISIPRequestProcessor { @@ -77,14 +87,19 @@ public class MessageRequestProcessor implements ISIPRequestProcessor {
77 Request request = evt.getRequest(); 87 Request request = evt.getRequest();
78 88
79 if (new String(request.getRawContent()).contains("<CmdType>Keepalive</CmdType>")) { 89 if (new String(request.getRawContent()).contains("<CmdType>Keepalive</CmdType>")) {
  90 + logger.info("接收到KeepAlive消息");
80 processMessageKeepAlive(evt); 91 processMessageKeepAlive(evt);
81 } else if (new String(request.getRawContent()).contains("<CmdType>Catalog</CmdType>")) { 92 } else if (new String(request.getRawContent()).contains("<CmdType>Catalog</CmdType>")) {
  93 + logger.info("接收到Catalog消息");
82 processMessageCatalogList(evt); 94 processMessageCatalogList(evt);
83 } else if (new String(request.getRawContent()).contains("<CmdType>DeviceInfo</CmdType>")) { 95 } else if (new String(request.getRawContent()).contains("<CmdType>DeviceInfo</CmdType>")) {
  96 + logger.info("接收到DeviceInfo消息");
84 processMessageDeviceInfo(evt); 97 processMessageDeviceInfo(evt);
85 } else if (new String(request.getRawContent()).contains("<CmdType>Alarm</CmdType>")) { 98 } else if (new String(request.getRawContent()).contains("<CmdType>Alarm</CmdType>")) {
  99 + logger.info("接收到Alarm消息");
86 processMessageAlarm(evt); 100 processMessageAlarm(evt);
87 - } else if (new String(request.getRawContent()).contains("<CmdType>recordInfo</CmdType>")) { 101 + } else if (new String(request.getRawContent()).contains("<CmdType>RecordInfo</CmdType>")) {
  102 + logger.info("接收到RecordInfo消息");
88 processMessageRecordInfo(evt); 103 processMessageRecordInfo(evt);
89 } 104 }
90 105
@@ -245,6 +260,7 @@ public class MessageRequestProcessor implements ISIPRequestProcessor { @@ -245,6 +260,7 @@ public class MessageRequestProcessor implements ISIPRequestProcessor {
245 260
246 /*** 261 /***
247 * 收到catalog设备目录列表请求 处理 262 * 收到catalog设备目录列表请求 处理
  263 + * TODO 过期时间暂时写死180秒,后续与DeferredResult超时时间保持一致
248 * @param evt 264 * @param evt
249 */ 265 */
250 private void processMessageRecordInfo(RequestEvent evt) { 266 private void processMessageRecordInfo(RequestEvent evt) {
@@ -256,15 +272,15 @@ public class MessageRequestProcessor implements ISIPRequestProcessor { @@ -256,15 +272,15 @@ public class MessageRequestProcessor implements ISIPRequestProcessor {
256 recordInfo.setDeviceId(deviceId); 272 recordInfo.setDeviceId(deviceId);
257 recordInfo.setName(XmlUtil.getText(rootElement,"Name")); 273 recordInfo.setName(XmlUtil.getText(rootElement,"Name"));
258 recordInfo.setSumNum(Integer.parseInt(XmlUtil.getText(rootElement,"SumNum"))); 274 recordInfo.setSumNum(Integer.parseInt(XmlUtil.getText(rootElement,"SumNum")));
  275 + String sn = XmlUtil.getText(rootElement,"SN");
259 Element recordListElement = rootElement.element("RecordList"); 276 Element recordListElement = rootElement.element("RecordList");
260 if (recordListElement == null) { 277 if (recordListElement == null) {
261 return; 278 return;
262 } 279 }
263 280
264 Iterator<Element> recordListIterator = recordListElement.elementIterator(); 281 Iterator<Element> recordListIterator = recordListElement.elementIterator();
  282 + List<RecordItem> recordList = new ArrayList<RecordItem>();
265 if (recordListIterator != null) { 283 if (recordListIterator != null) {
266 -  
267 - List<RecordItem> recordList = new ArrayList<RecordItem>();  
268 RecordItem record = new RecordItem(); 284 RecordItem record = new RecordItem();
269 // 遍历DeviceList 285 // 遍历DeviceList
270 while (recordListIterator.hasNext()) { 286 while (recordListIterator.hasNext()) {
@@ -273,6 +289,7 @@ public class MessageRequestProcessor implements ISIPRequestProcessor { @@ -273,6 +289,7 @@ public class MessageRequestProcessor implements ISIPRequestProcessor {
273 if (recordElement == null) { 289 if (recordElement == null) {
274 continue; 290 continue;
275 } 291 }
  292 + record = new RecordItem();
276 record.setDeviceId(XmlUtil.getText(itemRecord,"DeviceID")); 293 record.setDeviceId(XmlUtil.getText(itemRecord,"DeviceID"));
277 record.setName(XmlUtil.getText(itemRecord,"Name")); 294 record.setName(XmlUtil.getText(itemRecord,"Name"));
278 record.setFilePath(XmlUtil.getText(itemRecord,"FilePath")); 295 record.setFilePath(XmlUtil.getText(itemRecord,"FilePath"));
@@ -281,13 +298,42 @@ public class MessageRequestProcessor implements ISIPRequestProcessor { @@ -281,13 +298,42 @@ public class MessageRequestProcessor implements ISIPRequestProcessor {
281 record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(XmlUtil.getText(itemRecord,"EndTime"))); 298 record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(XmlUtil.getText(itemRecord,"EndTime")));
282 record.setSecrecy(itemRecord.element("Secrecy") == null? 0:Integer.parseInt(XmlUtil.getText(itemRecord,"Secrecy"))); 299 record.setSecrecy(itemRecord.element("Secrecy") == null? 0:Integer.parseInt(XmlUtil.getText(itemRecord,"Secrecy")));
283 record.setType(XmlUtil.getText(itemRecord,"Type")); 300 record.setType(XmlUtil.getText(itemRecord,"Type"));
284 - record.setRecordId(XmlUtil.getText(itemRecord,"RecordID")); 301 + record.setRecordId(XmlUtil.getText(itemRecord,"RecorderID"));
285 recordList.add(record); 302 recordList.add(record);
286 } 303 }
287 recordInfo.setRecordList(recordList); 304 recordInfo.setRecordList(recordList);
288 } 305 }
289 306
290 - 307 + // 存在录像且如果当前录像明细个数小于总条数,说明拆包返回,需要组装,暂不返回
  308 + if (recordInfo.getSumNum() > 0 && recordList.size() > 0 && recordList.size() < recordInfo.getSumNum()) {
  309 + // 为防止连续请求该设备的录像数据,返回数据错乱,特增加sn进行区分
  310 + String cacheKey = CACHE_RECORDINFO_KEY+deviceId+sn;
  311 + // TODO 暂时直接操作redis存储,后续封装专用缓存接口,改为本地内存缓存
  312 + if (redis.hasKey(cacheKey)) {
  313 + List<RecordItem> previousList = (List<RecordItem>) redis.get(cacheKey);
  314 + if (previousList != null && previousList.size() > 0) {
  315 + recordList.addAll(previousList);
  316 + }
  317 + // 本分支表示录像列表被拆包,且加上之前的数据还是不够,保存缓存返回,等待下个包再处理
  318 + if (recordList.size() < recordInfo.getSumNum()) {
  319 + redis.set(cacheKey, recordList, 180);
  320 + return;
  321 + } else {
  322 + // 本分支表示录像被拆包,但加上之前的数据够足够,返回响应
  323 + // 因设备心跳有监听redis过期机制,为提高性能,此处手动删除
  324 + redis.del(cacheKey);
  325 + }
  326 + } else {
  327 + // 本分支有两种可能:1、录像列表被拆包,且是第一个包,直接保存缓存返回,等待下个包再处理
  328 + // 2、之前有包,但超时清空了,那么这次sn批次的响应数据已经不完整,等待过期时间后redis自动清空数据
  329 + redis.set(cacheKey, recordList, 180);
  330 + return;
  331 + }
  332 +
  333 + }
  334 + // 走到这里,有以下可能:1、没有录像信息,第一次收到recordinfo的消息即返回响应数据,无redis操作
  335 + // 2、有录像数据,且第一次即收到完整数据,返回响应数据,无redis操作
  336 + // 3、有录像数据,在超时时间内收到多次包组装后数量足够,返回数据
291 RequestMessage msg = new RequestMessage(); 337 RequestMessage msg = new RequestMessage();
292 msg.setDeviceId(deviceId); 338 msg.setDeviceId(deviceId);
293 msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO); 339 msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java
@@ -45,7 +45,7 @@ import gov.nist.javax.sip.header.Expires; @@ -45,7 +45,7 @@ import gov.nist.javax.sip.header.Expires;
45 public class RegisterRequestProcessor implements ISIPRequestProcessor { 45 public class RegisterRequestProcessor implements ISIPRequestProcessor {
46 46
47 @Autowired 47 @Autowired
48 - private SipConfig config; 48 + private SipConfig sipConfig;
49 49
50 @Autowired 50 @Autowired
51 private RegisterLogicHandler handler; 51 private RegisterLogicHandler handler;
@@ -77,7 +77,7 @@ public class RegisterRequestProcessor implements ISIPRequestProcessor { @@ -77,7 +77,7 @@ public class RegisterRequestProcessor implements ISIPRequestProcessor {
77 // 校验密码是否正确 77 // 校验密码是否正确
78 if (authorhead != null) { 78 if (authorhead != null) {
79 passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request, 79 passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request,
80 - config.getSipPassword()); 80 + sipConfig.getSipPassword());
81 } 81 }
82 82
83 // 未携带授权头或者密码错误 回复401 83 // 未携带授权头或者密码错误 回复401
@@ -89,7 +89,7 @@ public class RegisterRequestProcessor implements ISIPRequestProcessor { @@ -89,7 +89,7 @@ public class RegisterRequestProcessor implements ISIPRequestProcessor {
89 System.out.println("密码错误 回复401"); 89 System.out.println("密码错误 回复401");
90 } 90 }
91 response = layer.getMessageFactory().createResponse(Response.UNAUTHORIZED, request); 91 response = layer.getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
92 - new DigestServerAuthenticationHelper().generateChallenge(layer.getHeaderFactory(), response, config.getSipDomain()); 92 + new DigestServerAuthenticationHelper().generateChallenge(layer.getHeaderFactory(), response, sipConfig.getSipDomain());
93 } 93 }
94 // 携带授权头并且密码正确 94 // 携带授权头并且密码正确
95 else if (passwordCorrect) { 95 else if (passwordCorrect) {
src/main/java/com/genersoft/iot/vmp/gb28181/utils/DateUtil.java
@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.utils; @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.utils;
2 2
3 import java.text.ParseException; 3 import java.text.ParseException;
4 import java.text.SimpleDateFormat; 4 import java.text.SimpleDateFormat;
  5 +import java.util.Date;
5 import java.util.Locale; 6 import java.util.Locale;
6 7
7 /** 8 /**
@@ -11,7 +12,8 @@ import java.util.Locale; @@ -11,7 +12,8 @@ import java.util.Locale;
11 */ 12 */
12 public class DateUtil { 13 public class DateUtil {
13 14
14 - private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; 15 + //private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
  16 + private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss";
15 private static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss"; 17 private static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
16 18
17 public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) { 19 public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) {
@@ -37,4 +39,19 @@ public class DateUtil { @@ -37,4 +39,19 @@ public class DateUtil {
37 } 39 }
38 return ""; 40 return "";
39 } 41 }
  42 +
  43 + public static long yyyy_MM_dd_HH_mm_ssToTimestamp(String formatTime) {
  44 + SimpleDateFormat format=new SimpleDateFormat(yyyy_MM_dd_HH_mm_ss);
  45 + //设置要读取的时间字符串格式
  46 + Date date;
  47 + try {
  48 + date = format.parse(formatTime);
  49 + Long timestamp=date.getTime();
  50 + //转换为Date类
  51 + return timestamp;
  52 + } catch (ParseException e) {
  53 + e.printStackTrace();
  54 + }
  55 + return 0;
  56 + }
40 } 57 }
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SsrcUtil.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.utils;
  2 +
  3 +import java.util.ArrayList;
  4 +import java.util.List;
  5 +import java.util.Random;
  6 +
  7 +import com.genersoft.iot.vmp.conf.SipConfig;
  8 +import com.genersoft.iot.vmp.utils.SpringBeanFactory;
  9 +
  10 +/**
  11 + * @Description:SIP信令中的SSRC工具类。SSRC值由10位十进制整数组成的字符串,第一位为0代表实况,为1则代表回放;第二位至第六位由监控域ID的第4位到第8位组成;最后4位为不重复的4个整数
  12 + * @author: songww
  13 + * @date: 2020年5月10日 上午11:57:57
  14 + */
  15 +public class SsrcUtil {
  16 +
  17 + private static String ssrcPrefix;
  18 +
  19 + private static List<String> isUsed;
  20 +
  21 + private static List<String> notUsed;
  22 +
  23 + private static void init() {
  24 + SipConfig sipConfig = (SipConfig) SpringBeanFactory.getBean("sipConfig");
  25 + ssrcPrefix = sipConfig.getSipDomain().substring(4, 9);
  26 + isUsed = new ArrayList<String>();
  27 + notUsed = new ArrayList<String>();
  28 + for (int i = 1; i < 10000; i++) {
  29 + if (i < 10) {
  30 + notUsed.add("000" + i);
  31 + } else if (i < 100) {
  32 + notUsed.add("00" + i);
  33 + } else if (i < 1000) {
  34 + notUsed.add("0" + i);
  35 + } else {
  36 + notUsed.add(String.valueOf(i));
  37 + }
  38 + }
  39 + }
  40 +
  41 + /**
  42 + * 获取视频预览的SSRC值,第一位固定为0
  43 + *
  44 + */
  45 + public static String getPlaySsrc() {
  46 + return "0" + getSsrcPrefix() + getSN();
  47 + }
  48 +
  49 + /**
  50 + * 获取录像回放的SSRC值,第一位固定为1
  51 + *
  52 + */
  53 + public static String getPlayBackSsrc() {
  54 + return "1" + getSsrcPrefix() + getSN();
  55 + }
  56 +
  57 + /**
  58 + * 释放ssrc,主要用完的ssrc一定要释放,否则会耗尽
  59 + *
  60 + */
  61 + public static void releaseSsrc(String ssrc) {
  62 + String sn = ssrc.substring(6);
  63 + isUsed.remove(sn);
  64 + notUsed.add(sn);
  65 + }
  66 +
  67 + /**
  68 + * 获取后四位数SN,随机数
  69 + *
  70 + */
  71 + private static String getSN() {
  72 + String sn = null;
  73 + if (notUsed.size() == 0) {
  74 + throw new RuntimeException("ssrc已经用完");
  75 + } else if (notUsed.size() == 1) {
  76 + sn = notUsed.get(0);
  77 + } else {
  78 + sn = notUsed.get(new Random().nextInt(notUsed.size() - 1));
  79 + }
  80 + notUsed.remove(0);
  81 + isUsed.add(sn);
  82 + return sn;
  83 + }
  84 +
  85 + private static String getSsrcPrefix() {
  86 + if (ssrcPrefix == null) {
  87 + init();
  88 + }
  89 + return ssrcPrefix;
  90 + }
  91 +}
src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java 0 → 100644
  1 +package com.genersoft.iot.vmp.utils;
  2 +
  3 +import org.springframework.beans.BeansException;
  4 +import org.springframework.context.ApplicationContext;
  5 +import org.springframework.context.ApplicationContextAware;
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +/**
  9 + * @Description:spring bean获取工厂,获取spring中的已初始化的bean
  10 + * @author: songww
  11 + * @date: 2019年6月25日 下午4:51:52
  12 + *
  13 + */
  14 +@Component
  15 +public class SpringBeanFactory implements ApplicationContextAware {
  16 +
  17 + // Spring应用上下文环境
  18 + private static ApplicationContext applicationContext;
  19 +
  20 + /**
  21 + * 实现ApplicationContextAware接口的回调方法,设置上下文环境
  22 + */
  23 + @Override
  24 + public void setApplicationContext(ApplicationContext applicationContext)
  25 + throws BeansException {
  26 + SpringBeanFactory.applicationContext = applicationContext;
  27 + }
  28 +
  29 + public static ApplicationContext getApplicationContext() {
  30 + return applicationContext;
  31 + }
  32 +
  33 + /**
  34 + * 获取对象 这里重写了bean方法,起主要作用
  35 + */
  36 + public static Object getBean(String beanId) throws BeansException {
  37 + return applicationContext.getBean(beanId);
  38 + }
  39 +
  40 + /**
  41 + * 获取当前环境
  42 + */
  43 + public static String getActiveProfile() {
  44 + return applicationContext.getEnvironment().getActiveProfiles()[0];
  45 + }
  46 +
  47 +}
src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java
1 package com.genersoft.iot.vmp.vmanager.device; 1 package com.genersoft.iot.vmp.vmanager.device;
2 2
3 import java.util.List; 3 import java.util.List;
4 -import java.util.concurrent.ExecutorService;  
5 -import java.util.concurrent.Executors;  
6 4
7 import org.slf4j.Logger; 5 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory; 6 import org.slf4j.LoggerFactory;
src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.playback;
  2 +
  3 +import org.slf4j.Logger;
  4 +import org.slf4j.LoggerFactory;
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.http.HttpStatus;
  7 +import org.springframework.http.ResponseEntity;
  8 +import org.springframework.web.bind.annotation.GetMapping;
  9 +import org.springframework.web.bind.annotation.PathVariable;
  10 +import org.springframework.web.bind.annotation.RequestMapping;
  11 +import org.springframework.web.bind.annotation.RestController;
  12 +
  13 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  14 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  15 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  16 +
  17 +@RestController
  18 +@RequestMapping("/api")
  19 +public class PlaybackController {
  20 +
  21 + private final static Logger logger = LoggerFactory.getLogger(PlaybackController.class);
  22 +
  23 + @Autowired
  24 + private SIPCommander cmder;
  25 +
  26 + @Autowired
  27 + private IVideoManagerStorager storager;
  28 +
  29 + @GetMapping("/playback/{deviceId}/{channelId}")
  30 + public ResponseEntity<String> play(@PathVariable String deviceId,@PathVariable String channelId, String startTime, String endTime){
  31 +
  32 + Device device = storager.queryVideoDevice(deviceId);
  33 + String ssrc = cmder.playStreamCmd(device, channelId);
  34 +
  35 + if (logger.isDebugEnabled()) {
  36 + logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",deviceId, channelId));
  37 + logger.debug("设备预览 API调用,ssrc:"+ssrc+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(ssrc)));
  38 + }
  39 +
  40 + if(ssrc!=null) {
  41 + return new ResponseEntity<String>(ssrc,HttpStatus.OK);
  42 + } else {
  43 + logger.warn("设备预览API调用失败!");
  44 + return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
  45 + }
  46 + }
  47 +}
src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java
@@ -5,8 +5,8 @@ import org.slf4j.LoggerFactory; @@ -5,8 +5,8 @@ import org.slf4j.LoggerFactory;
5 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.beans.factory.annotation.Autowired;
6 import org.springframework.http.HttpStatus; 6 import org.springframework.http.HttpStatus;
7 import org.springframework.http.ResponseEntity; 7 import org.springframework.http.ResponseEntity;
8 -import org.springframework.web.bind.annotation.GetMapping;  
9 import org.springframework.web.bind.annotation.PathVariable; 8 import org.springframework.web.bind.annotation.PathVariable;
  9 +import org.springframework.web.bind.annotation.PostMapping;
10 import org.springframework.web.bind.annotation.RequestMapping; 10 import org.springframework.web.bind.annotation.RequestMapping;
11 import org.springframework.web.bind.annotation.RestController; 11 import org.springframework.web.bind.annotation.RestController;
12 12
@@ -37,7 +37,7 @@ public class PtzController { @@ -37,7 +37,7 @@ public class PtzController {
37 * @param zoomSpeed 37 * @param zoomSpeed
38 * @return 38 * @return
39 */ 39 */
40 - @GetMapping("/ptz/{deviceId}_{channelId}") 40 + @PostMapping("/ptz/{deviceId}/{channelId}")
41 public ResponseEntity<String> ptz(@PathVariable String deviceId,@PathVariable String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed){ 41 public ResponseEntity<String> ptz(@PathVariable String deviceId,@PathVariable String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed){
42 42
43 if (logger.isDebugEnabled()) { 43 if (logger.isDebugEnabled()) {
src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java
@@ -31,17 +31,18 @@ public class RecordController { @@ -31,17 +31,18 @@ public class RecordController {
31 @Autowired 31 @Autowired
32 private DeferredResultHolder resultHolder; 32 private DeferredResultHolder resultHolder;
33 33
34 - @GetMapping("/recordinfo/{deviceId}")  
35 - public DeferredResult<ResponseEntity<RecordInfo>> recordinfo(@PathVariable String deviceId, String startTime, String endTime){ 34 + @GetMapping("/record/{deviceId}")
  35 + public DeferredResult<ResponseEntity<RecordInfo>> recordinfo(@PathVariable String deviceId, String channelId, String startTime, String endTime){
36 36
37 if (logger.isDebugEnabled()) { 37 if (logger.isDebugEnabled()) {
38 logger.debug(String.format("录像信息 API调用,deviceId:%s ,startTime:%s, startTime:%s",deviceId, startTime, endTime)); 38 logger.debug(String.format("录像信息 API调用,deviceId:%s ,startTime:%s, startTime:%s",deviceId, startTime, endTime));
39 } 39 }
40 40
41 Device device = storager.queryVideoDevice(deviceId); 41 Device device = storager.queryVideoDevice(deviceId);
42 - cmder.recordInfoQuery(device, startTime, endTime); 42 + cmder.recordInfoQuery(device, channelId, startTime, endTime);
43 DeferredResult<ResponseEntity<RecordInfo>> result = new DeferredResult<ResponseEntity<RecordInfo>>(); 43 DeferredResult<ResponseEntity<RecordInfo>> result = new DeferredResult<ResponseEntity<RecordInfo>>();
44 - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result); 44 + // 录像查询以channelId作为deviceId查询
  45 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_RECORDINFO+channelId, result);
45 return result; 46 return result;
46 } 47 }
47 } 48 }
src/main/resources/application.yml
1 spring: 1 spring:
2 application: 2 application:
3 - name: wvp  
4 - # 数据存储方式,暂只支持redis,后续支持jdbc 3 + name: iot-vmp-vmanager
  4 + # 影子数据存储方式,支持redis、jdbc
5 database: redis 5 database: redis
  6 + # 通信方式,支持kafka、http
  7 + communicate: http
6 redis: 8 redis:
7 # Redis服务器IP 9 # Redis服务器IP
  10 + #host: 10.24.20.63
8 host: 127.0.0.1 11 host: 127.0.0.1
9 #端口号 12 #端口号
10 port: 6379 13 port: 6379
@@ -13,24 +16,49 @@ spring: @@ -13,24 +16,49 @@ spring:
13 password: 16 password:
14 #超时时间 17 #超时时间
15 timeout: 10000 18 timeout: 10000
  19 + # 可用连接实例的最大数目,默认值为8
  20 + maxTotal: 512
  21 + #控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8
  22 + maxIdle: 100
  23 + #最小空闲连接数
  24 + minIdle: 50
  25 + #获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1
  26 + maxWaitMillis: 10000
  27 + #每次释放连接的最大数目
  28 + numTestsPerEvictionRun: 100
  29 + #释放连接的扫描间隔(毫秒)
  30 + timeBetweenEvictionRunsMillis: 3000
  31 + #连接最小空闲时间
  32 + minEvictableIdleTimeMillis: 1800000
  33 + #连接空闲多久后释放,当空闲时间>该值且空闲连接>最大空闲连接数时直接释放
  34 + softMinEvictableIdleTimeMillis: 10000
  35 + #在获取连接的时候检查有效性,默认false
  36 + testOnBorrow: true
  37 + #在空闲时检查有效性,默认false
  38 + testWhileIdle: true
  39 + #在归还给pool时,是否提前进行validate操作
  40 + testOnReturn: true
  41 + #连接耗尽时是否阻塞,false报异常,ture阻塞直到超时,默认true
  42 + blockWhenExhausted: false
16 datasource: 43 datasource:
17 - name: wcp  
18 - url: jdbc:mysql://127.0.0.1:3306/wcp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true 44 + name: eiot
  45 + url: jdbc:mysql://10.24.20.63:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
19 username: root 46 username: root
20 - password: 123456 47 + password: Ptjsinspur19.?
21 type: com.alibaba.druid.pool.DruidDataSource 48 type: com.alibaba.druid.pool.DruidDataSource
22 driver-class-name: com.mysql.jdbc.Driver 49 driver-class-name: com.mysql.jdbc.Driver
23 server: 50 server:
24 port: 8080 51 port: 8080
25 sip: 52 sip:
26 - # 本地服务地址  
27 - ip: 192.168.0.3  
28 - server_id: 34020000002000000001 53 + ip: 10.200.64.63
29 port: 5060 54 port: 5060
30 - domain: 34020000  
31 - # 暂时使用统一密码,后续改为一机一密 55 + # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007)
  56 + # 后两位为行业编码,定义参照附录D.3
  57 + # 3701020049标识山东济南历下区 信息行业接入
  58 + domain: 3701020049
  59 + server_id: 37010200492000000001
  60 + # 默认设备认证密码,后续扩展使用设备单独密码
32 password: admin 61 password: admin
33 media: 62 media:
34 - # ZLMediaServer IP  
35 - ip: 192.168.0.4 63 + ip: 10.200.64.88
36 port: 10000 64 port: 10000
37 \ No newline at end of file 65 \ No newline at end of file