From 6ecd801c2365feb4e65f6684065aa97f11615797 Mon Sep 17 00:00:00 2001 From: songww Date: Wed, 13 May 2020 20:38:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AE=BE=E5=A4=87=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=8E=A5=E5=8F=A3=EF=BC=8C=E5=8F=AA=E5=85=81=E8=AE=B8?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E7=A6=BB=E7=BA=BF=E8=AE=BE=E5=A4=87=EF=BC=9B?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A7=86=E9=A2=91=E5=81=9C=E6=AD=A2=E6=92=AD?= =?UTF-8?q?=E6=94=BE=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/genersoft/iot/vmp/conf/SipConfig.java | 12 +++- .../genersoft/iot/vmp/gb28181/SipLayer.java | 4 +- .../gb28181/{utils => session}/SsrcUtil.java | 2 +- .../session/VideoStreamSessionManager.java | 41 ++++++++++++ .../gb28181/transmit/cmd/ISIPCommander.java | 7 ++ .../cmd/SIPRequestHeaderProvider.java | 57 ++++++++++++++-- .../transmit/cmd/impl/SIPCommander.java | 67 +++++++++++++++---- .../request/ISIPRequestProcessor.java | 3 +- .../request/impl/AckRequestProcessor.java | 2 +- .../request/impl/ByeRequestProcessor.java | 2 +- .../request/impl/CancelRequestProcessor.java | 2 +- .../request/impl/InviteRequestProcessor.java | 2 +- .../request/impl/MessageRequestProcessor.java | 4 +- .../request/impl/OtherRequestProcessor.java | 2 +- .../impl/RegisterRequestProcessor.java | 4 +- .../impl/SubscribeRequestProcessor.java | 4 +- .../impl/InviteResponseProcessor.java | 46 +++++++------ .../redis/VideoManagerRedisStoragerImpl.java | 3 +- .../iot/vmp/utils/redis/RedisUtil.java | 20 ++++-- .../vmp/vmanager/device/DeviceController.java | 26 +++++++ .../iot/vmp/vmanager/play/PlayController.java | 20 ++++++ src/main/resources/application.yml | 2 +- 22 files changed, 266 insertions(+), 66 deletions(-) rename src/main/java/com/genersoft/iot/vmp/gb28181/{utils => session}/SsrcUtil.java (93%) create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java 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 339389ff..2694de38 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java @@ -12,6 +12,8 @@ public class SipConfig { Integer sipPort; @Value("${sip.domain}") String sipDomain; + @Value("${sip.id}") + String sipId; @Value("${sip.password}") String sipPassword; @Value("${media.ip}") @@ -77,6 +79,12 @@ public class SipConfig { public void setSpeed(Integer speed) { this.speed = speed; } - - + + public String getSipId() { + return sipId; + } + + public void setSipId(String sipId) { + this.sipId = sipId; + } } 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 2f585d2c..cfea0262 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java @@ -117,7 +117,7 @@ public class SipLayer implements SipListener, Runnable { @Override public void processRequest(RequestEvent evt) { ISIPRequestProcessor processor = processorFactory.createRequestProcessor(evt); - processor.process(evt, this, getServerTransaction(evt)); + processor.process(evt, this); } @Override @@ -200,7 +200,7 @@ public class SipLayer implements SipListener, Runnable { } - private ServerTransaction getServerTransaction(RequestEvent evt) { + public ServerTransaction getServerTransaction(RequestEvent evt) { Request request = evt.getRequest(); ServerTransaction serverTransaction = evt.getServerTransaction(); // 判断TCP还是UDP diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SsrcUtil.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcUtil.java similarity index 93% rename from src/main/java/com/genersoft/iot/vmp/gb28181/utils/SsrcUtil.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcUtil.java index 023b4f95..9e887dae 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SsrcUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcUtil.java @@ -1,4 +1,4 @@ -package com.genersoft.iot.vmp.gb28181.utils; +package com.genersoft.iot.vmp.gb28181.session; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java new file mode 100644 index 00000000..f8b93505 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java @@ -0,0 +1,41 @@ +package com.genersoft.iot.vmp.gb28181.session; + +import java.util.concurrent.ConcurrentHashMap; + +import javax.sip.ClientTransaction; + +import org.springframework.stereotype.Component; + +/** + * @Description:视频流session管理器,管理视频预览、预览回放的通信句柄 + * @author: songww + * @date: 2020年5月13日 下午4:03:02 + */ +@Component +public class VideoStreamSessionManager { + + private ConcurrentHashMap sessionMap = new ConcurrentHashMap<>(); + + public String createPlaySsrc(){ + String ssrc = SsrcUtil.getPlaySsrc(); + return ssrc; + } + + public String createPlayBackSsrc(){ + String ssrc = SsrcUtil.getPlayBackSsrc(); + return ssrc; + } + + public void put(String ssrc,ClientTransaction transaction){ + sessionMap.put(ssrc, transaction); + } + + public ClientTransaction get(String ssrc){ + return sessionMap.get(ssrc); + } + + public void remove(String ssrc) { + sessionMap.remove(ssrc); + SsrcUtil.releaseSsrc(ssrc); + } +} 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 1039a356..8b190d5c 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 @@ -81,6 +81,13 @@ public interface ISIPCommander { */ public String playbackStreamCmd(Device device,String channelId, String startTime, String endTime); + /** + * 视频流停止 + * + * @param ssrc ssrc + */ + public void streamByeCmd(String ssrc); + /** * 语音广播 * 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 5adbf66a..b4eb4d21 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 @@ -46,14 +46,15 @@ public class SIPRequestHeaderProvider { ArrayList viaHeaders = new ArrayList(); 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(), + SipURI fromSipURI = layer.getAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp() + ":" + sipConfig.getSipPort()); Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI); FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); // to - SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); + SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain()); Address toAddress = layer.getAddressFactory().createAddress(toSipURI); ToHeader toHeader = layer.getHeaderFactory().createToHeader(toAddress, toTag); // callid @@ -71,6 +72,49 @@ public class SIPRequestHeaderProvider { return request; } +// public Request createInviteRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException { +// Request request = null; +// Host host = device.getHost(); +// //请求行 +// SipURI requestLine = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); +// //via +// ArrayList viaHeaders = new ArrayList(); +// 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(),sipConfig.getSipIp()+":"+sipConfig.getSipPort()); +// Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI); +// FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack +// //to +// SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),host.getAddress()); +// Address toAddress = layer.getAddressFactory().createAddress(toSipURI); +// ToHeader toHeader = layer.getHeaderFactory().createToHeader(toAddress,null); +// +// //callid +// CallIdHeader callIdHeader = null; +// if(device.getTransport().equals("TCP")) { +// callIdHeader = layer.getTcpSipProvider().getNewCallId(); +// } +// if(device.getTransport().equals("UDP")) { +// callIdHeader = layer.getUdpSipProvider().getNewCallId(); +// } +// +// //Forwards +// MaxForwardsHeader maxForwards = layer.getHeaderFactory().createMaxForwardsHeader(70); +// +// //ceq +// CSeqHeader cSeqHeader = layer.getHeaderFactory().createCSeqHeader(1L, Request.INVITE); +// request = layer.getMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); +// +// Address concatAddress = layer.getAddressFactory().createAddress(layer.getAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); +// request.addHeader(layer.getHeaderFactory().createContactHeader(concatAddress)); +// +// ContentTypeHeader contentTypeHeader = layer.getHeaderFactory().createContentTypeHeader("Application", "SDP"); +// request.setContent(content, contentTypeHeader); +// return request; +// } + public Request createInviteRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException { Request request = null; Host host = device.getHost(); @@ -82,11 +126,11 @@ public class SIPRequestHeaderProvider { viaHeader.setRPort(); viaHeaders.add(viaHeader); //from - SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),sipConfig.getSipIp()+":"+sipConfig.getSipPort()); + SipURI fromSipURI = layer.getAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain()); Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI); FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack //to - SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),host.getAddress()); + SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),sipConfig.getSipDomain()); Address toAddress = layer.getAddressFactory().createAddress(toSipURI); ToHeader toHeader = layer.getHeaderFactory().createToHeader(toAddress,null); @@ -101,9 +145,14 @@ public class SIPRequestHeaderProvider { //Forwards MaxForwardsHeader maxForwards = layer.getHeaderFactory().createMaxForwardsHeader(70); + //ceq CSeqHeader cSeqHeader = layer.getHeaderFactory().createCSeqHeader(1L, Request.INVITE); request = layer.getMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); + + Address concatAddress = layer.getAddressFactory().createAddress(layer.getAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); + request.addHeader(layer.getHeaderFactory().createContactHeader(concatAddress)); + ContentTypeHeader contentTypeHeader = layer.getHeaderFactory().createContentTypeHeader("Application", "SDP"); request.setContent(content, contentTypeHeader); return request; 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 a6b512ff..6213d7d5 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 @@ -3,8 +3,11 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; import java.text.ParseException; import javax.sip.ClientTransaction; +import javax.sip.Dialog; import javax.sip.InvalidArgumentException; import javax.sip.SipException; +import javax.sip.TransactionDoesNotExistException; +import javax.sip.header.ViaHeader; import javax.sip.message.Request; import org.springframework.beans.factory.annotation.Autowired; @@ -13,10 +16,10 @@ import org.springframework.stereotype.Component; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.gb28181.SipLayer; import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 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; /** * @Description:设备能力接口,用于定义设备的控制、查询能力 @@ -35,6 +38,9 @@ public class SIPCommander implements ISIPCommander { @Autowired private SipLayer sipLayer; + @Autowired + private VideoStreamSessionManager streamSession; + /** * 云台方向放控制,使用配置文件中的默认镜头移动速度 * @@ -135,11 +141,11 @@ public class SIPCommander implements ISIPCommander { public String playStreamCmd(Device device, String channelId) { try { - String ssrc = SsrcUtil.getPlaySsrc(); + String ssrc = streamSession.createPlaySsrc(); // 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("o="+channelId+" 0 0 IN IP4 "+sipConfig.getMediaIp()+"\r\n"); content.append("s=Play\r\n"); content.append("c=IN IP4 "+sipConfig.getMediaIp()+"\r\n"); content.append("t=0 0\r\n"); @@ -161,7 +167,8 @@ public class SIPCommander implements ISIPCommander { Request request = headerProvider.createInviteRequest(device, content.toString(), null, "live", null); - transmitRequest(device, request); + ClientTransaction transaction = transmitRequest(device, request); + streamSession.put(ssrc, transaction); return ssrc; } catch ( SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); @@ -181,11 +188,11 @@ public class SIPCommander implements ISIPCommander { public String playbackStreamCmd(Device device, String channelId, String startTime, String endTime) { try { - String ssrc = SsrcUtil.getPlayBackSsrc(); + String ssrc = streamSession.createPlayBackSsrc(); // StringBuffer content = new StringBuffer(200); content.append("v=0\r\n"); - content.append("o="+device.getDeviceId()+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n"); + content.append("o="+device.getDeviceId()+" 0 0 IN IP4 "+sipConfig.getMediaIp()+"\r\n"); content.append("s=Playback\r\n"); content.append("u="+channelId+":3\r\n"); content.append("c=IN IP4 "+sipConfig.getMediaIp()+"\r\n"); @@ -208,13 +215,50 @@ public class SIPCommander implements ISIPCommander { Request request = headerProvider.createInviteRequest(device, content.toString(), null, "live", null); - transmitRequest(device, request); + ClientTransaction transaction = transmitRequest(device, request); + streamSession.put(ssrc, transaction); return ssrc; } catch ( SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); return null; } } + + /** + * 视频流停止 + * + * @param device 视频设备 + * @param channelId 预览通道 + */ + @Override + public void streamByeCmd(String ssrc) { + + try { + ClientTransaction transaction = streamSession.get(ssrc); + if (transaction == null) { + return; + } + + Dialog dialog = transaction.getDialog(); + if (dialog == null) { + return; + } + Request byeRequest = dialog.createRequest(Request.BYE); + ViaHeader viaHeader = (ViaHeader) byeRequest.getHeader(ViaHeader.NAME); + String protocol = viaHeader.getTransport(); + ClientTransaction clientTransaction = null; + if("TCP".equals(protocol)) { + clientTransaction = sipLayer.getTcpSipProvider().getNewClientTransaction(byeRequest); + } else if("UDP".equals(protocol)) { + clientTransaction = sipLayer.getUdpSipProvider().getNewClientTransaction(byeRequest); + } + dialog.sendRequest(clientTransaction); + } catch (TransactionDoesNotExistException e) { + e.printStackTrace(); + } catch (SipException e) { + e.printStackTrace(); + } + } /** * 语音广播 @@ -435,16 +479,15 @@ public class SIPCommander implements ISIPCommander { return false; } - private void transmitRequest(Device device, Request request) throws SipException { + private ClientTransaction transmitRequest(Device device, Request request) throws SipException { ClientTransaction clientTransaction = null; - if(device.getTransport().equals("TCP")) { + if("TCP".equals(device.getTransport())) { clientTransaction = sipLayer.getTcpSipProvider().getNewClientTransaction(request); - //sipLayer.getTcpSipProvider().sendRequest(request); - } else if(device.getTransport().equals("UDP")) { + } else if("UDP".equals(device.getTransport())) { clientTransaction = sipLayer.getUdpSipProvider().getNewClientTransaction(request); - //sipLayer.getUdpSipProvider().sendRequest(request); } clientTransaction.sendRequest(); + return clientTransaction; } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/ISIPRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/ISIPRequestProcessor.java index a1757f21..53e0ed0f 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/ISIPRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/ISIPRequestProcessor.java @@ -1,7 +1,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.request; import javax.sip.RequestEvent; -import javax.sip.ServerTransaction; import com.genersoft.iot.vmp.gb28181.SipLayer; @@ -12,6 +11,6 @@ import com.genersoft.iot.vmp.gb28181.SipLayer; */ public interface ISIPRequestProcessor { - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction); + public void process(RequestEvent evt, SipLayer layer); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java index f26d566e..7a5b25d6 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java @@ -31,7 +31,7 @@ public class AckRequestProcessor implements ISIPRequestProcessor { * @param config */ @Override - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { + public void process(RequestEvent evt, SipLayer layer) { Request request = evt.getRequest(); Dialog dialog = evt.getDialog(); try { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java index 20dd82f4..716f4827 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java @@ -25,7 +25,7 @@ public class ByeRequestProcessor implements ISIPRequestProcessor { * @param config */ @Override - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { + public void process(RequestEvent evt, SipLayer layer) { // TODO Auto-generated method stub } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/CancelRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/CancelRequestProcessor.java index c5008290..d463af45 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/CancelRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/CancelRequestProcessor.java @@ -25,7 +25,7 @@ public class CancelRequestProcessor implements ISIPRequestProcessor { * @param config */ @Override - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { + public void process(RequestEvent evt, SipLayer layer) { // TODO Auto-generated method stub } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java index 17b592a9..0de32c9e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java @@ -23,7 +23,7 @@ public class InviteRequestProcessor implements ISIPRequestProcessor { * 请求消息 */ @Override - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { + public void process(RequestEvent evt, SipLayer layer) { // TODO Auto-generated method stub // Request request = requestEvent.getRequest(); // 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 8a7c6cfb..fd5ca377 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 @@ -93,10 +93,10 @@ public class MessageRequestProcessor implements ISIPRequestProcessor { * @param transaction */ @Override - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { + public void process(RequestEvent evt, SipLayer layer) { this.layer = layer; - this.transaction = transaction; + this.transaction = layer.getServerTransaction(evt); Request request = evt.getRequest(); SAXReader reader = new SAXReader(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/OtherRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/OtherRequestProcessor.java index 227240d8..e5167671 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/OtherRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/OtherRequestProcessor.java @@ -25,7 +25,7 @@ public class OtherRequestProcessor implements ISIPRequestProcessor { * @param config */ @Override - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { + public void process(RequestEvent evt, SipLayer layer) { System.out.println("no support the method! Method:" + evt.getRequest().getMethod()); } 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 7ca2e439..ca1ba5d7 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 @@ -63,7 +63,7 @@ public class RegisterRequestProcessor implements ISIPRequestProcessor { * 请求消息 */ @Override - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { + public void process(RequestEvent evt, SipLayer layer) { try { System.out.println("收到注册请求,开始处理"); Request request = evt.getRequest(); @@ -141,7 +141,7 @@ public class RegisterRequestProcessor implements ISIPRequestProcessor { device.setTransport(isTcp ? "TCP" : "UDP"); } } - transaction.sendResponse(response); + layer.getServerTransaction(evt).sendResponse(response); // 注册成功 // 保存到redis // 下发catelog查询目录 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java index 47761d09..b0c05a82 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java @@ -32,7 +32,7 @@ public class SubscribeRequestProcessor implements ISIPRequestProcessor { * @param config */ @Override - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { + public void process(RequestEvent evt, SipLayer layer) { Request request = evt.getRequest(); try { @@ -43,7 +43,7 @@ public class SubscribeRequestProcessor implements ISIPRequestProcessor { response.setExpires(expireHeader); } System.out.println("response : " + response.toString()); - + ServerTransaction transaction = layer.getServerTransaction(evt); if (transaction != null) { transaction.sendResponse(response); transaction.terminate(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java index f825584c..9b1783f8 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java @@ -50,31 +50,33 @@ public class InviteResponseProcessor implements ISIPResponseProcessor { //成功响应 //下发ack if(statusCode == Response.OK){ - ClientTransaction clientTransaction = evt.getClientTransaction(); - if(clientTransaction == null){ - logger.error("回复ACK时,clientTransaction为null >>> {}",response); - return; - } - Dialog clientDialog = clientTransaction.getDialog(); - - CSeqHeader clientCSeqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME); - long cseqId = clientCSeqHeader.getSeqNumber(); - /* - createAck函数,创建的ackRequest,会采用Invite响应的200OK,中的contact字段中的地址,作为目标地址。 - 有的终端传上来的可能还是内网地址,会造成ack发送不出去。接受不到音视频流 - 所以在此处统一替换地址。和响应消息的Via头中的地址保持一致。 - */ - Request ackRequest = clientDialog.createAck(cseqId); - SipURI requestURI = (SipURI) ackRequest.getRequestURI(); - ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME); - requestURI.setHost(viaHeader.getHost()); - requestURI.setPort(viaHeader.getPort()); - clientDialog.sendAck(ackRequest); +// ClientTransaction clientTransaction = evt.getClientTransaction(); +// if(clientTransaction == null){ +// logger.error("回复ACK时,clientTransaction为null >>> {}",response); +// return; +// } +// Dialog clientDialog = clientTransaction.getDialog(); +// +// CSeqHeader clientCSeqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME); +// long cseqId = clientCSeqHeader.getSeqNumber(); +// /* +// createAck函数,创建的ackRequest,会采用Invite响应的200OK,中的contact字段中的地址,作为目标地址。 +// 有的终端传上来的可能还是内网地址,会造成ack发送不出去。接受不到音视频流 +// 所以在此处统一替换地址。和响应消息的Via头中的地址保持一致。 +// */ +// Request ackRequest = clientDialog.createAck(cseqId); +// SipURI requestURI = (SipURI) ackRequest.getRequestURI(); +// ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME); +// requestURI.setHost(viaHeader.getHost()); +// requestURI.setPort(viaHeader.getPort()); +// clientDialog.sendAck(ackRequest); + + Dialog dialog = evt.getDialog(); + Request reqAck =dialog.createAck(1L); + dialog.sendAck(reqAck); } } catch (InvalidArgumentException | SipException e) { e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); } } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java index cad5e1fa..54fa692e 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java @@ -96,8 +96,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { */ @Override public boolean delete(String deviceId) { - redis.del(VideoManagerConstants.CACHEKEY_PREFIX+deviceId); - return true; + return redis.del(VideoManagerConstants.CACHEKEY_PREFIX+deviceId); } /** diff --git a/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java index 0427f8b7..a03f9aa1 100644 --- a/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java @@ -68,14 +68,20 @@ public class RedisUtil { * @SuppressWarnings("unchecked") 忽略类型转换警告 * @param key 键(一个或者多个) */ - public void del(String... key) { - if (key != null && key.length > 0) { - if (key.length == 1) { - redisTemplate.delete(key[0]); - } else { -// 传入一个 Collection 集合 - redisTemplate.delete(CollectionUtils.arrayToList(key)); + public boolean del(String... key) { + try { + if (key != null && key.length > 0) { + if (key.length == 1) { + redisTemplate.delete(key[0]); + } else { +// 传入一个 Collection 集合 + redisTemplate.delete(CollectionUtils.arrayToList(key)); + } } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; } } 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 3115933d..60b48b11 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 @@ -14,7 +14,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; +import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; @@ -34,6 +36,9 @@ public class DeviceController { @Autowired private DeferredResultHolder resultHolder; + @Autowired + private DeviceOffLineDetector offLineDetector; + @GetMapping("/devices/{deviceId}") public ResponseEntity devices(@PathVariable String deviceId){ @@ -69,4 +74,25 @@ public class DeviceController { resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result); return result; } + + @PostMapping("/devices/{deviceId}/delete") + public ResponseEntity delete(@PathVariable String deviceId){ + + if (logger.isDebugEnabled()) { + logger.debug("设备信息删除API调用,deviceId:" + deviceId); + } + + if (offLineDetector.isOnline(deviceId)) { + return new ResponseEntity("不允许删除在线设备!", HttpStatus.NOT_ACCEPTABLE); + } + boolean isSuccess = storager.delete(deviceId); + if (isSuccess) { + JSONObject json = new JSONObject(); + json.put("deviceId", deviceId); + return new ResponseEntity<>(json.toString(),HttpStatus.OK); + } else { + logger.warn("设备预览API调用失败!"); + return new ResponseEntity("设备预览API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); + } + } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java index 93703556..51e5074e 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java @@ -7,6 +7,7 @@ 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; @@ -47,4 +48,23 @@ public class PlayController { return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); } } + + @PostMapping("/play/{ssrc}/stop") + public ResponseEntity playStop(@PathVariable String ssrc){ + + cmder.streamByeCmd(ssrc); + + if (logger.isDebugEnabled()) { + logger.debug(String.format("设备预览停止API调用,ssrc:%s", ssrc)); + } + + if(ssrc!=null) { + JSONObject json = new JSONObject(); + json.put("ssrc", ssrc); + return new ResponseEntity(json.toString(),HttpStatus.OK); + } else { + logger.warn("设备预览停止API调用失败!"); + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 02dc489a..4ec320e8 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -26,7 +26,7 @@ spring: server: port: 8080 sip: - ip: 127.0.0.1 + ip: 10.200.64.63 port: 5060 # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) # 后两位为行业编码,定义参照附录D.3