From 3a502b36a8cfcdd455edb22e5771115559873731 Mon Sep 17 00:00:00 2001 From: songww <songww@inspur.com> Date: 星期日, 10 五月 2020 22:33:21 +0800 Subject: [PATCH] 完善ssrc符合国标,并完善很多小问题 --- src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java | 10 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java | 96 +++++++++--- src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java | 2 src/main/java/com/genersoft/iot/vmp/gb28181/utils/DateUtil.java | 19 ++ src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java | 47 +++++ src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java | 12 + src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java | 4 src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java | 14 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java | 10 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java | 6 src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java | 2 src/main/java/com/genersoft/iot/vmp/gb28181/utils/SsrcUtil.java | 91 +++++++++++ src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java | 58 ++++++ src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java | 47 +++++ src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java | 9 src/main/resources/application.yml | 52 +++++- 16 files changed, 406 insertions(+), 73 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java index 6d53033..339389f 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java @@ -3,7 +3,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; -@Configuration +@Configuration("sipConfig") public class SipConfig { @Value("${sip.ip}") diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java index 273f4ed..2f585d2 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java @@ -42,7 +42,7 @@ private final static Logger logger = LoggerFactory.getLogger(SipLayer.class); @Autowired - private SipConfig config; + private SipConfig sipConfig; private SipProvider tcpSipProvider; @@ -77,7 +77,7 @@ Properties properties = new Properties(); properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); - properties.setProperty("javax.sip.IP_ADDRESS", config.getSipIp()); + properties.setProperty("javax.sip.IP_ADDRESS", sipConfig.getSipIp()); properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "false"); /** * sip_server_log.log 鍜� sip_debug_log.log public static final int TRACE_NONE = @@ -92,20 +92,20 @@ startTcpListener(); startUdpListener(); } catch (Exception e) { - logger.error("Sip Server 鍚姩澶辫触锛� port {" + config.getSipPort() + "}"); + logger.error("Sip Server 鍚姩澶辫触锛� port {" + sipConfig.getSipPort() + "}"); e.printStackTrace(); } - logger.info("Sip Server 鍚姩鎴愬姛 port {" + config.getSipPort() + "}"); + logger.info("Sip Server 鍚姩鎴愬姛 port {" + sipConfig.getSipPort() + "}"); } private void startTcpListener() throws Exception { - ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(config.getSipIp(), config.getSipPort(), "TCP"); + ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getSipIp(), sipConfig.getSipPort(), "TCP"); tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint); tcpSipProvider.addSipListener(this); } private void startUdpListener() throws Exception { - ListeningPoint udpListeningPoint = sipStack.createListeningPoint(config.getSipIp(), config.getSipPort(), "UDP"); + ListeningPoint udpListeningPoint = sipStack.createListeningPoint(sipConfig.getSipIp(), sipConfig.getSipPort(), "UDP"); udpSipProvider = sipStack.createSipProvider(udpListeningPoint); udpSipProvider.addSipListener(this); } @@ -126,7 +126,7 @@ int status = response.getStatusCode(); if ((status >= 200) && (status < 300)) { // Success! ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt); - processor.process(evt, this, config); + processor.process(evt, this, sipConfig); } else { logger.warn("鎺ユ敹鍒板け璐ョ殑response鍝嶅簲锛乻tatus锛�" + status + ",message:" + response.getContent().toString()); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java index b0e713b..484c25e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java @@ -23,7 +23,7 @@ private String type; - private String recordId; + private String recorderId; public String getDeviceId() { return deviceId; @@ -81,12 +81,12 @@ this.type = type; } - public String getRecordId() { - return recordId; + public String getRecorderId() { + return recorderId; } - public void setRecordId(String recordId) { - this.recordId = recordId; + public void setRecordId(String recorderId) { + this.recorderId = recorderId; } public String getEndTime() { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java index f226bf5..b0fa6cd 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java @@ -72,6 +72,16 @@ public String playStreamCmd(Device device,String channelId); /** + * 璇锋眰鍥炴斁瑙嗛娴� + * + * @param device 瑙嗛璁惧 + * @param channelId 棰勮閫氶亾 + * @param startTime 寮�濮嬫椂闂�,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss + * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss + */ + public String playbackStreamCmd(Device device,String channelId, String recordId, String startTime, String endTime); + + /** * 璇煶骞挎挱 * * @param device 瑙嗛璁惧 @@ -153,7 +163,7 @@ * @param startTime 寮�濮嬫椂闂�,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss */ - public boolean recordInfoQuery(Device device, String startTime, String endTime); + public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime); /** * 鏌ヨ鎶ヨ淇℃伅 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java index 55aa9fe..5adbf66 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java @@ -35,7 +35,7 @@ private SipLayer layer; @Autowired - private SipConfig config; + private SipConfig sipConfig; public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException { Request request = null; @@ -44,12 +44,12 @@ SipURI requestURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); // via ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); - ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(config.getSipIp(), config.getSipPort(), + ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag); viaHeaders.add(viaHeader); // from SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), - config.getSipIp() + ":" + config.getSipPort()); + sipConfig.getSipIp() + ":" + sipConfig.getSipPort()); Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI); FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); // to @@ -78,11 +78,11 @@ SipURI requestLine = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); //via ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); - ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(config.getSipIp(), config.getSipPort(), device.getTransport(), viaTag); + ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag); viaHeader.setRPort(); viaHeaders.add(viaHeader); //from - SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),config.getSipIp()+":"+config.getSipPort()); + SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),sipConfig.getSipIp()+":"+sipConfig.getSipPort()); Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI); FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); //蹇呴』瑕佹湁鏍囪锛屽惁鍒欐棤娉曞垱寤轰細璇濓紝鏃犳硶鍥炲簲ack //to diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 630d44c..b012f9a 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -17,6 +17,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; import com.genersoft.iot.vmp.gb28181.utils.DateUtil; +import com.genersoft.iot.vmp.gb28181.utils.SsrcUtil; + +import tk.mybatis.mapper.util.StringUtil; /** * @Description:璁惧鑳藉姏鎺ュ彛锛岀敤浜庡畾涔夎澶囩殑鎺у埗銆佹煡璇㈣兘鍔� @@ -27,7 +30,7 @@ public class SIPCommander implements ISIPCommander { @Autowired - private SipConfig config; + private SipConfig sipConfig; @Autowired private SIPRequestHeaderProvider headerProvider; @@ -46,7 +49,7 @@ */ @Override public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) { - return ptzCmd(device, channelId, leftRight, upDown, 0, config.getSpeed(), 0); + return ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getSpeed(), 0); } /** @@ -72,7 +75,7 @@ */ @Override public boolean ptzZoomCmd(Device device, String channelId, int inOut) { - return ptzCmd(device, channelId, 0, 0, inOut, 0, config.getSpeed()); + return ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getSpeed()); } /** @@ -135,23 +138,19 @@ public String playStreamCmd(Device device, String channelId) { try { - //鐢熸垚ssrc鏍囪瘑鏁版嵁娴� 10浣嶆暟瀛� - String ssrc = ""; - Random random = new Random(); - // ZLMediaServer鏈�澶ц瘑鍒�7FFFFFFF鍗�2147483647锛屾墍浠ラ殢鏈烘暟涓嶈兘瓒呰繃杩欎釜鏁� - ssrc = String.valueOf(random.nextInt(2147483647)); + String ssrc = SsrcUtil.getPlaySsrc(); // StringBuffer content = new StringBuffer(200); content.append("v=0\r\n"); - content.append("o="+channelId+" 0 0 IN IP4 "+config.getSipIp()+"\r\n"); + content.append("o="+channelId+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n"); content.append("s=Play\r\n"); - content.append("c=IN IP4 "+config.getMediaIp()+"\r\n"); + content.append("c=IN IP4 "+sipConfig.getMediaIp()+"\r\n"); content.append("t=0 0\r\n"); if(device.getTransport().equals("TCP")) { - content.append("m=video "+config.getMediaPort()+" TCP/RTP/AVP 96 98 97\r\n"); + content.append("m=video "+sipConfig.getMediaPort()+" TCP/RTP/AVP 96 98 97\r\n"); } if(device.getTransport().equals("UDP")) { - content.append("m=video "+config.getMediaPort()+" RTP/AVP 96 98 97\r\n"); + content.append("m=video "+sipConfig.getMediaPort()+" RTP/AVP 96 98 97\r\n"); } content.append("a=sendrecv\r\n"); content.append("a=rtpmap:96 PS/90000\r\n"); @@ -171,6 +170,53 @@ e.printStackTrace(); return null; } + } + + /** + * 璇锋眰鍥炴斁瑙嗛娴� + * + * @param device 瑙嗛璁惧 + * @param channelId 棰勮閫氶亾 + * @param startTime 寮�濮嬫椂闂�,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss + * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss + */ + @Override + public String playbackStreamCmd(Device device, String channelId, String recordId, String startTime, String endTime) { + try { + + String ssrc = SsrcUtil.getPlayBackSsrc(); + // + StringBuffer content = new StringBuffer(200); + content.append("v=0\r\n"); + content.append("o="+channelId+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n"); + content.append("s=Playback\r\n"); + content.append("u="+recordId+":3\r\n"); + content.append("c=IN IP4 "+sipConfig.getMediaIp()+"\r\n"); + content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n"); + if(device.getTransport().equals("TCP")) { + content.append("m=video "+sipConfig.getMediaPort()+" TCP/RTP/AVP 96 98 97\r\n"); + } + if(device.getTransport().equals("UDP")) { + content.append("m=video "+sipConfig.getMediaPort()+" RTP/AVP 96 98 97\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + if(device.getTransport().equals("TCP")){ + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + } + content.append("y="+ssrc+"\r\n");//ssrc + + Request request = headerProvider.createInviteRequest(device, content.toString(), null, "live", null); + + transmitRequest(device, request); + return ssrc; + } catch ( SipException | ParseException | InvalidArgumentException e) { + e.printStackTrace(); + return null; + } } /** @@ -323,22 +369,23 @@ * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss */ @Override - public boolean recordInfoQuery(Device device, String startTime, String endTime) { + public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime) { try { - StringBuffer catalogXml = new StringBuffer(200); - catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>"); - catalogXml.append("<Query>"); - catalogXml.append("<CmdType>RecordInfo</CmdType>"); - catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>"); - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>"); - catalogXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>"); - catalogXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>"); + StringBuffer recordInfoXml = new StringBuffer(200); + recordInfoXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>"); + recordInfoXml.append("<Query>"); + recordInfoXml.append("<CmdType>RecordInfo</CmdType>"); + recordInfoXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>"); + recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>"); + recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>"); + recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>"); + recordInfoXml.append("<Secrecy>0</Secrecy>"); // 澶у崕NVR瑕佹眰蹇呴』澧炲姞涓�涓�间负all鐨勬枃鏈厓绱犺妭鐐筎ype - catalogXml.append("<Type>all</Type>"); - catalogXml.append("</Query>"); + recordInfoXml.append("<Type>all</Type>"); + recordInfoXml.append("</Query>"); - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", "ToRecordInfoTag"); + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", "ToRecordInfoTag"); transmitRequest(device, request); } catch (SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); @@ -398,4 +445,5 @@ sipLayer.getUdpSipProvider().sendRequest(request); } } + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java index 453420a..9a39d5c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java @@ -19,6 +19,8 @@ import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -36,6 +38,7 @@ import com.genersoft.iot.vmp.gb28181.utils.DateUtil; import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.utils.redis.RedisUtil; /** * @Description:MESSAGE璇锋眰澶勭悊鍣� @@ -44,7 +47,9 @@ */ @Component public class MessageRequestProcessor implements ISIPRequestProcessor { - + + private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class); + private ServerTransaction transaction; private SipLayer layer; @@ -59,7 +64,12 @@ private EventPublisher publisher; @Autowired + private RedisUtil redis; + + @Autowired private DeferredResultHolder deferredResultHolder; + + private final static String CACHE_RECORDINFO_KEY = "CACHE_RECORDINFO_"; /** * 澶勭悊MESSAGE璇锋眰 @@ -77,14 +87,19 @@ Request request = evt.getRequest(); if (new String(request.getRawContent()).contains("<CmdType>Keepalive</CmdType>")) { + logger.info("鎺ユ敹鍒癒eepAlive娑堟伅"); processMessageKeepAlive(evt); } else if (new String(request.getRawContent()).contains("<CmdType>Catalog</CmdType>")) { + logger.info("鎺ユ敹鍒癈atalog娑堟伅"); processMessageCatalogList(evt); } else if (new String(request.getRawContent()).contains("<CmdType>DeviceInfo</CmdType>")) { + logger.info("鎺ユ敹鍒癉eviceInfo娑堟伅"); processMessageDeviceInfo(evt); } else if (new String(request.getRawContent()).contains("<CmdType>Alarm</CmdType>")) { + logger.info("鎺ユ敹鍒癆larm娑堟伅"); processMessageAlarm(evt); - } else if (new String(request.getRawContent()).contains("<CmdType>recordInfo</CmdType>")) { + } else if (new String(request.getRawContent()).contains("<CmdType>RecordInfo</CmdType>")) { + logger.info("鎺ユ敹鍒癛ecordInfo娑堟伅"); processMessageRecordInfo(evt); } @@ -245,6 +260,7 @@ /*** * 鏀跺埌catalog璁惧鐩綍鍒楄〃璇锋眰 澶勭悊 + * TODO 杩囨湡鏃堕棿鏆傛椂鍐欐180绉掞紝鍚庣画涓嶥eferredResult瓒呮椂鏃堕棿淇濇寔涓�鑷� * @param evt */ private void processMessageRecordInfo(RequestEvent evt) { @@ -256,15 +272,15 @@ recordInfo.setDeviceId(deviceId); recordInfo.setName(XmlUtil.getText(rootElement,"Name")); recordInfo.setSumNum(Integer.parseInt(XmlUtil.getText(rootElement,"SumNum"))); + String sn = XmlUtil.getText(rootElement,"SN"); Element recordListElement = rootElement.element("RecordList"); if (recordListElement == null) { return; } Iterator<Element> recordListIterator = recordListElement.elementIterator(); + List<RecordItem> recordList = new ArrayList<RecordItem>(); if (recordListIterator != null) { - - List<RecordItem> recordList = new ArrayList<RecordItem>(); RecordItem record = new RecordItem(); // 閬嶅巻DeviceList while (recordListIterator.hasNext()) { @@ -273,6 +289,7 @@ if (recordElement == null) { continue; } + record = new RecordItem(); record.setDeviceId(XmlUtil.getText(itemRecord,"DeviceID")); record.setName(XmlUtil.getText(itemRecord,"Name")); record.setFilePath(XmlUtil.getText(itemRecord,"FilePath")); @@ -281,13 +298,42 @@ record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(XmlUtil.getText(itemRecord,"EndTime"))); record.setSecrecy(itemRecord.element("Secrecy") == null? 0:Integer.parseInt(XmlUtil.getText(itemRecord,"Secrecy"))); record.setType(XmlUtil.getText(itemRecord,"Type")); - record.setRecordId(XmlUtil.getText(itemRecord,"RecordID")); + record.setRecordId(XmlUtil.getText(itemRecord,"RecorderID")); recordList.add(record); } recordInfo.setRecordList(recordList); } - + // 瀛樺湪褰曞儚涓斿鏋滃綋鍓嶅綍鍍忔槑缁嗕釜鏁板皬浜庢�绘潯鏁帮紝璇存槑鎷嗗寘杩斿洖锛岄渶瑕佺粍瑁咃紝鏆備笉杩斿洖 + if (recordInfo.getSumNum() > 0 && recordList.size() > 0 && recordList.size() < recordInfo.getSumNum()) { + // 涓洪槻姝㈣繛缁姹傝璁惧鐨勫綍鍍忔暟鎹紝杩斿洖鏁版嵁閿欎贡锛岀壒澧炲姞sn杩涜鍖哄垎 + String cacheKey = CACHE_RECORDINFO_KEY+deviceId+sn; + // TODO 鏆傛椂鐩存帴鎿嶄綔redis瀛樺偍锛屽悗缁皝瑁呬笓鐢ㄧ紦瀛樻帴鍙o紝鏀逛负鏈湴鍐呭瓨缂撳瓨 + if (redis.hasKey(cacheKey)) { + List<RecordItem> previousList = (List<RecordItem>) redis.get(cacheKey); + if (previousList != null && previousList.size() > 0) { + recordList.addAll(previousList); + } + // 鏈垎鏀〃绀哄綍鍍忓垪琛ㄨ鎷嗗寘锛屼笖鍔犱笂涔嬪墠鐨勬暟鎹繕鏄笉澶�,淇濆瓨缂撳瓨杩斿洖锛岀瓑寰呬笅涓寘鍐嶅鐞� + if (recordList.size() < recordInfo.getSumNum()) { + redis.set(cacheKey, recordList, 180); + return; + } else { + // 鏈垎鏀〃绀哄綍鍍忚鎷嗗寘锛屼絾鍔犱笂涔嬪墠鐨勬暟鎹瓒冲锛岃繑鍥炲搷搴� + // 鍥犺澶囧績璺虫湁鐩戝惉redis杩囨湡鏈哄埗锛屼负鎻愰珮鎬ц兘锛屾澶勬墜鍔ㄥ垹闄� + redis.del(cacheKey); + } + } else { + // 鏈垎鏀湁涓ょ鍙兘锛�1銆佸綍鍍忓垪琛ㄨ鎷嗗寘锛屼笖鏄涓�涓寘,鐩存帴淇濆瓨缂撳瓨杩斿洖锛岀瓑寰呬笅涓寘鍐嶅鐞� + // 2銆佷箣鍓嶆湁鍖咃紝浣嗚秴鏃舵竻绌轰簡锛岄偅涔堣繖娆n鎵规鐨勫搷搴旀暟鎹凡缁忎笉瀹屾暣锛岀瓑寰呰繃鏈熸椂闂村悗redis鑷姩娓呯┖鏁版嵁 + redis.set(cacheKey, recordList, 180); + return; + } + + } + // 璧板埌杩欓噷锛屾湁浠ヤ笅鍙兘锛�1銆佹病鏈夊綍鍍忎俊鎭�,绗竴娆℃敹鍒皉ecordinfo鐨勬秷鎭嵆杩斿洖鍝嶅簲鏁版嵁锛屾棤redis鎿嶄綔 + // 2銆佹湁褰曞儚鏁版嵁锛屼笖绗竴娆″嵆鏀跺埌瀹屾暣鏁版嵁锛岃繑鍥炲搷搴旀暟鎹紝鏃爎edis鎿嶄綔 + // 3銆佹湁褰曞儚鏁版嵁锛屽湪瓒呮椂鏃堕棿鍐呮敹鍒板娆″寘缁勮鍚庢暟閲忚冻澶燂紝杩斿洖鏁版嵁 RequestMessage msg = new RequestMessage(); msg.setDeviceId(deviceId); msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java index ebb6db4..7ca2e43 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java @@ -45,7 +45,7 @@ public class RegisterRequestProcessor implements ISIPRequestProcessor { @Autowired - private SipConfig config; + private SipConfig sipConfig; @Autowired private RegisterLogicHandler handler; @@ -77,7 +77,7 @@ // 鏍¢獙瀵嗙爜鏄惁姝g‘ if (authorhead != null) { passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request, - config.getSipPassword()); + sipConfig.getSipPassword()); } // 鏈惡甯︽巿鏉冨ご鎴栬�呭瘑鐮侀敊璇� 鍥炲401 @@ -89,7 +89,7 @@ System.out.println("瀵嗙爜閿欒 鍥炲401"); } response = layer.getMessageFactory().createResponse(Response.UNAUTHORIZED, request); - new DigestServerAuthenticationHelper().generateChallenge(layer.getHeaderFactory(), response, config.getSipDomain()); + new DigestServerAuthenticationHelper().generateChallenge(layer.getHeaderFactory(), response, sipConfig.getSipDomain()); } // 鎼哄甫鎺堟潈澶村苟涓斿瘑鐮佹纭� else if (passwordCorrect) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/DateUtil.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/DateUtil.java index e241bd5..5950d17 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/DateUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/DateUtil.java @@ -2,6 +2,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Date; import java.util.Locale; /** @@ -11,7 +12,8 @@ */ public class DateUtil { - private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; + //private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; + private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss"; private static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss"; public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) { @@ -37,4 +39,19 @@ } return ""; } + + public static long yyyy_MM_dd_HH_mm_ssToTimestamp(String formatTime) { + SimpleDateFormat format=new SimpleDateFormat(yyyy_MM_dd_HH_mm_ss); + //璁剧疆瑕佽鍙栫殑鏃堕棿瀛楃涓叉牸寮� + Date date; + try { + date = format.parse(formatTime); + Long timestamp=date.getTime(); + //杞崲涓篋ate绫� + return timestamp; + } catch (ParseException e) { + e.printStackTrace(); + } + return 0; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SsrcUtil.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SsrcUtil.java new file mode 100644 index 0000000..023b4f9 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SsrcUtil.java @@ -0,0 +1,91 @@ +package com.genersoft.iot.vmp.gb28181.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import com.genersoft.iot.vmp.conf.SipConfig; +import com.genersoft.iot.vmp.utils.SpringBeanFactory; + +/** + * @Description:SIP淇′护涓殑SSRC宸ュ叿绫汇�係SRC鍊肩敱10浣嶅崄杩涘埗鏁存暟缁勬垚鐨勫瓧绗︿覆锛岀涓�浣嶄负0浠h〃瀹炲喌锛屼负1鍒欎唬琛ㄥ洖鏀撅紱绗簩浣嶈嚦绗叚浣嶇敱鐩戞帶鍩烮D鐨勭4浣嶅埌绗�8浣嶇粍鎴愶紱鏈�鍚�4浣嶄负涓嶉噸澶嶇殑4涓暣鏁� + * @author: songww + * @date: 2020骞�5鏈�10鏃� 涓婂崍11:57:57 + */ +public class SsrcUtil { + + private static String ssrcPrefix; + + private static List<String> isUsed; + + private static List<String> notUsed; + + private static void init() { + SipConfig sipConfig = (SipConfig) SpringBeanFactory.getBean("sipConfig"); + ssrcPrefix = sipConfig.getSipDomain().substring(4, 9); + isUsed = new ArrayList<String>(); + notUsed = new ArrayList<String>(); + for (int i = 1; i < 10000; i++) { + if (i < 10) { + notUsed.add("000" + i); + } else if (i < 100) { + notUsed.add("00" + i); + } else if (i < 1000) { + notUsed.add("0" + i); + } else { + notUsed.add(String.valueOf(i)); + } + } + } + + /** + * 鑾峰彇瑙嗛棰勮鐨凷SRC鍊�,绗竴浣嶅浐瀹氫负0 + * + */ + public static String getPlaySsrc() { + return "0" + getSsrcPrefix() + getSN(); + } + + /** + * 鑾峰彇褰曞儚鍥炴斁鐨凷SRC鍊�,绗竴浣嶅浐瀹氫负1 + * + */ + public static String getPlayBackSsrc() { + return "1" + getSsrcPrefix() + getSN(); + } + + /** + * 閲婃斁ssrc锛屼富瑕佺敤瀹岀殑ssrc涓�瀹氳閲婃斁锛屽惁鍒欎細鑰楀敖 + * + */ + public static void releaseSsrc(String ssrc) { + String sn = ssrc.substring(6); + isUsed.remove(sn); + notUsed.add(sn); + } + + /** + * 鑾峰彇鍚庡洓浣嶆暟SN,闅忔満鏁� + * + */ + private static String getSN() { + String sn = null; + if (notUsed.size() == 0) { + throw new RuntimeException("ssrc宸茬粡鐢ㄥ畬"); + } else if (notUsed.size() == 1) { + sn = notUsed.get(0); + } else { + sn = notUsed.get(new Random().nextInt(notUsed.size() - 1)); + } + notUsed.remove(0); + isUsed.add(sn); + return sn; + } + + private static String getSsrcPrefix() { + if (ssrcPrefix == null) { + init(); + } + return ssrcPrefix; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java b/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java new file mode 100644 index 0000000..273f5fb --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java @@ -0,0 +1,47 @@ +package com.genersoft.iot.vmp.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * @Description:spring bean鑾峰彇宸ュ巶锛岃幏鍙杝pring涓殑宸插垵濮嬪寲鐨刡ean + * @author: songww + * @date: 2019骞�6鏈�25鏃� 涓嬪崍4:51:52 + * + */ +@Component +public class SpringBeanFactory implements ApplicationContextAware { + + // Spring搴旂敤涓婁笅鏂囩幆澧� + private static ApplicationContext applicationContext; + + /** + * 瀹炵幇ApplicationContextAware鎺ュ彛鐨勫洖璋冩柟娉曪紝璁剧疆涓婁笅鏂囩幆澧� + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + SpringBeanFactory.applicationContext = applicationContext; + } + + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + /** + * 鑾峰彇瀵硅薄 杩欓噷閲嶅啓浜哹ean鏂规硶锛岃捣涓昏浣滅敤 + */ + public static Object getBean(String beanId) throws BeansException { + return applicationContext.getBean(beanId); + } + + /** + * 鑾峰彇褰撳墠鐜 + */ + public static String getActiveProfile() { + return applicationContext.getEnvironment().getActiveProfiles()[0]; + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java index ce86910..3115933 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java @@ -1,8 +1,6 @@ package com.genersoft.iot.vmp.vmanager.device; import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java new file mode 100644 index 0000000..4be6110 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java @@ -0,0 +1,47 @@ +package com.genersoft.iot.vmp.vmanager.playback; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; + +@RestController +@RequestMapping("/api") +public class PlaybackController { + + private final static Logger logger = LoggerFactory.getLogger(PlaybackController.class); + + @Autowired + private SIPCommander cmder; + + @Autowired + private IVideoManagerStorager storager; + + @GetMapping("/playback/{deviceId}/{channelId}") + public ResponseEntity<String> play(@PathVariable String deviceId,@PathVariable String channelId, String startTime, String endTime){ + + Device device = storager.queryVideoDevice(deviceId); + String ssrc = cmder.playStreamCmd(device, channelId); + + if (logger.isDebugEnabled()) { + logger.debug(String.format("璁惧棰勮 API璋冪敤锛宒eviceId锛�%s 锛宑hannelId锛�%s",deviceId, channelId)); + logger.debug("璁惧棰勮 API璋冪敤锛宻src锛�"+ssrc+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(ssrc))); + } + + if(ssrc!=null) { + return new ResponseEntity<String>(ssrc,HttpStatus.OK); + } else { + logger.warn("璁惧棰勮API璋冪敤澶辫触锛�"); + return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java index bc9792e..29279ef 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java @@ -5,8 +5,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -37,7 +37,7 @@ * @param zoomSpeed * @return */ - @GetMapping("/ptz/{deviceId}_{channelId}") + @PostMapping("/ptz/{deviceId}/{channelId}") public ResponseEntity<String> ptz(@PathVariable String deviceId,@PathVariable String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed){ if (logger.isDebugEnabled()) { diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java index c115dd0..5b947c9 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java @@ -31,17 +31,18 @@ @Autowired private DeferredResultHolder resultHolder; - @GetMapping("/recordinfo/{deviceId}") - public DeferredResult<ResponseEntity<RecordInfo>> recordinfo(@PathVariable String deviceId, String startTime, String endTime){ + @GetMapping("/record/{deviceId}") + public DeferredResult<ResponseEntity<RecordInfo>> recordinfo(@PathVariable String deviceId, String channelId, String startTime, String endTime){ if (logger.isDebugEnabled()) { logger.debug(String.format("褰曞儚淇℃伅 API璋冪敤锛宒eviceId锛�%s 锛宻tartTime锛�%s锛� startTime锛�%s",deviceId, startTime, endTime)); } Device device = storager.queryVideoDevice(deviceId); - cmder.recordInfoQuery(device, startTime, endTime); + cmder.recordInfoQuery(device, channelId, startTime, endTime); DeferredResult<ResponseEntity<RecordInfo>> result = new DeferredResult<ResponseEntity<RecordInfo>>(); - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result); + // 褰曞儚鏌ヨ浠hannelId浣滀负deviceId鏌ヨ + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_RECORDINFO+channelId, result); return result; } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6314fa4..df0a190 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,10 +1,13 @@ spring: application: - name: wvp - # 鏁版嵁瀛樺偍鏂瑰紡锛屾殏鍙敮鎸乺edis锛屽悗缁敮鎸乯dbc + name: iot-vmp-vmanager + # 褰卞瓙鏁版嵁瀛樺偍鏂瑰紡锛屾敮鎸乺edis銆乯dbc database: redis + # 閫氫俊鏂瑰紡锛屾敮鎸乲afka銆乭ttp + communicate: http redis: # Redis鏈嶅姟鍣↖P + #host: 10.24.20.63 host: 127.0.0.1 #绔彛鍙� port: 6379 @@ -13,24 +16,49 @@ password: #瓒呮椂鏃堕棿 timeout: 10000 + # 鍙敤杩炴帴瀹炰緥鐨勬渶澶ф暟鐩紝榛樿鍊间负8 + maxTotal: 512 + #鎺у埗涓�涓猵ool鏈�澶氭湁澶氬皯涓姸鎬佷负idle(绌洪棽鐨�)鐨刯edis瀹炰緥锛岄粯璁ゅ�间篃鏄�8 + maxIdle: 100 + #鏈�灏忕┖闂茶繛鎺ユ暟 + minIdle: 50 + #鑾峰彇杩炴帴鏃剁殑鏈�澶х瓑寰呮绉掓暟,灏忎簬闆�:闃诲涓嶇‘瀹氱殑鏃堕棿,榛樿-1 + maxWaitMillis: 10000 + #姣忔閲婃斁杩炴帴鐨勬渶澶ф暟鐩� + numTestsPerEvictionRun: 100 + #閲婃斁杩炴帴鐨勬壂鎻忛棿闅旓紙姣锛� + timeBetweenEvictionRunsMillis: 3000 + #杩炴帴鏈�灏忕┖闂叉椂闂� + minEvictableIdleTimeMillis: 1800000 + #杩炴帴绌洪棽澶氫箙鍚庨噴鏀�,褰撶┖闂叉椂闂�>璇ュ�间笖绌洪棽杩炴帴>鏈�澶х┖闂茶繛鎺ユ暟鏃剁洿鎺ラ噴鏀� + softMinEvictableIdleTimeMillis: 10000 + #鍦ㄨ幏鍙栬繛鎺ョ殑鏃跺�欐鏌ユ湁鏁堟��,榛樿false + testOnBorrow: true + #鍦ㄧ┖闂叉椂妫�鏌ユ湁鏁堟��,榛樿false + testWhileIdle: true + #鍦ㄥ綊杩樼粰pool鏃讹紝鏄惁鎻愬墠杩涜validate鎿嶄綔 + testOnReturn: true + #杩炴帴鑰楀敖鏃舵槸鍚﹂樆濉�,false鎶ュ紓甯�,ture闃诲鐩村埌瓒呮椂,榛樿true + blockWhenExhausted: false datasource: - name: wcp - url: jdbc:mysql://127.0.0.1:3306/wcp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true + name: eiot + url: jdbc:mysql://10.24.20.63:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true username: root - password: 123456 + password: Ptjsinspur19.? type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver server: port: 8080 sip: - # 鏈湴鏈嶅姟鍦板潃 - ip: 192.168.0.3 - server_id: 34020000002000000001 + ip: 10.200.64.63 port: 5060 - domain: 34020000 - # 鏆傛椂浣跨敤缁熶竴瀵嗙爜锛屽悗缁敼涓轰竴鏈轰竴瀵� + # 鏍规嵁鍥芥爣6.1.2涓瀹氾紝domain瀹滈噰鐢↖D缁熶竴缂栫爜鐨勫墠鍗佷綅缂栫爜銆傚浗鏍囬檮褰旸涓畾涔夊墠8浣嶄负涓績缂栫爜锛堢敱鐪佺骇銆佸競绾с�佸尯绾с�佸熀灞傜紪鍙风粍鎴愶紝鍙傜収GB/T 2260-2007锛� + # 鍚庝袱浣嶄负琛屼笟缂栫爜锛屽畾涔夊弬鐓ч檮褰旸.3 + # 3701020049鏍囪瘑灞变笢娴庡崡鍘嗕笅鍖� 淇℃伅琛屼笟鎺ュ叆 + domain: 3701020049 + server_id: 37010200492000000001 + # 榛樿璁惧璁よ瘉瀵嗙爜锛屽悗缁墿灞曚娇鐢ㄨ澶囧崟鐙瘑鐮� password: admin media: - # ZLMediaServer IP - ip: 192.168.0.4 + ip: 10.200.64.88 port: 10000 \ No newline at end of file -- Gitblit v1.8.0