Commit 6ecd801c2365feb4e65f6684065aa97f11615797
1 parent
ca513992
增加设备删除接口,只允许删除离线设备;增加视频停止播放接口
Showing
22 changed files
with
266 additions
and
66 deletions
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
| ... | ... | @@ -12,6 +12,8 @@ public class SipConfig { |
| 12 | 12 | Integer sipPort; |
| 13 | 13 | @Value("${sip.domain}") |
| 14 | 14 | String sipDomain; |
| 15 | + @Value("${sip.id}") | |
| 16 | + String sipId; | |
| 15 | 17 | @Value("${sip.password}") |
| 16 | 18 | String sipPassword; |
| 17 | 19 | @Value("${media.ip}") |
| ... | ... | @@ -77,6 +79,12 @@ public class SipConfig { |
| 77 | 79 | public void setSpeed(Integer speed) { |
| 78 | 80 | this.speed = speed; |
| 79 | 81 | } |
| 80 | - | |
| 81 | - | |
| 82 | + | |
| 83 | + public String getSipId() { | |
| 84 | + return sipId; | |
| 85 | + } | |
| 86 | + | |
| 87 | + public void setSipId(String sipId) { | |
| 88 | + this.sipId = sipId; | |
| 89 | + } | |
| 82 | 90 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
| ... | ... | @@ -117,7 +117,7 @@ public class SipLayer implements SipListener, Runnable { |
| 117 | 117 | @Override |
| 118 | 118 | public void processRequest(RequestEvent evt) { |
| 119 | 119 | ISIPRequestProcessor processor = processorFactory.createRequestProcessor(evt); |
| 120 | - processor.process(evt, this, getServerTransaction(evt)); | |
| 120 | + processor.process(evt, this); | |
| 121 | 121 | } |
| 122 | 122 | |
| 123 | 123 | @Override |
| ... | ... | @@ -200,7 +200,7 @@ public class SipLayer implements SipListener, Runnable { |
| 200 | 200 | |
| 201 | 201 | } |
| 202 | 202 | |
| 203 | - private ServerTransaction getServerTransaction(RequestEvent evt) { | |
| 203 | + public ServerTransaction getServerTransaction(RequestEvent evt) { | |
| 204 | 204 | Request request = evt.getRequest(); |
| 205 | 205 | ServerTransaction serverTransaction = evt.getServerTransaction(); |
| 206 | 206 | // 判断TCP还是UDP | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SsrcUtil.java renamed to src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcUtil.java
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.gb28181.session; | |
| 2 | + | |
| 3 | +import java.util.concurrent.ConcurrentHashMap; | |
| 4 | + | |
| 5 | +import javax.sip.ClientTransaction; | |
| 6 | + | |
| 7 | +import org.springframework.stereotype.Component; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * @Description:视频流session管理器,管理视频预览、预览回放的通信句柄 | |
| 11 | + * @author: songww | |
| 12 | + * @date: 2020年5月13日 下午4:03:02 | |
| 13 | + */ | |
| 14 | +@Component | |
| 15 | +public class VideoStreamSessionManager { | |
| 16 | + | |
| 17 | + private ConcurrentHashMap<String, ClientTransaction> sessionMap = new ConcurrentHashMap<>(); | |
| 18 | + | |
| 19 | + public String createPlaySsrc(){ | |
| 20 | + String ssrc = SsrcUtil.getPlaySsrc(); | |
| 21 | + return ssrc; | |
| 22 | + } | |
| 23 | + | |
| 24 | + public String createPlayBackSsrc(){ | |
| 25 | + String ssrc = SsrcUtil.getPlayBackSsrc(); | |
| 26 | + return ssrc; | |
| 27 | + } | |
| 28 | + | |
| 29 | + public void put(String ssrc,ClientTransaction transaction){ | |
| 30 | + sessionMap.put(ssrc, transaction); | |
| 31 | + } | |
| 32 | + | |
| 33 | + public ClientTransaction get(String ssrc){ | |
| 34 | + return sessionMap.get(ssrc); | |
| 35 | + } | |
| 36 | + | |
| 37 | + public void remove(String ssrc) { | |
| 38 | + sessionMap.remove(ssrc); | |
| 39 | + SsrcUtil.releaseSsrc(ssrc); | |
| 40 | + } | |
| 41 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
| ... | ... | @@ -82,6 +82,13 @@ public interface ISIPCommander { |
| 82 | 82 | public String playbackStreamCmd(Device device,String channelId, String startTime, String endTime); |
| 83 | 83 | |
| 84 | 84 | /** |
| 85 | + * 视频流停止 | |
| 86 | + * | |
| 87 | + * @param ssrc ssrc | |
| 88 | + */ | |
| 89 | + public void streamByeCmd(String ssrc); | |
| 90 | + | |
| 91 | + /** | |
| 85 | 92 | * 语音广播 |
| 86 | 93 | * |
| 87 | 94 | * @param device 视频设备 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
| ... | ... | @@ -46,14 +46,15 @@ public class SIPRequestHeaderProvider { |
| 46 | 46 | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
| 47 | 47 | ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), |
| 48 | 48 | device.getTransport(), viaTag); |
| 49 | + viaHeader.setRPort(); | |
| 49 | 50 | viaHeaders.add(viaHeader); |
| 50 | 51 | // from |
| 51 | - SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), | |
| 52 | + SipURI fromSipURI = layer.getAddressFactory().createSipURI(sipConfig.getSipId(), | |
| 52 | 53 | sipConfig.getSipIp() + ":" + sipConfig.getSipPort()); |
| 53 | 54 | Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI); |
| 54 | 55 | FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); |
| 55 | 56 | // to |
| 56 | - SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); | |
| 57 | + SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain()); | |
| 57 | 58 | Address toAddress = layer.getAddressFactory().createAddress(toSipURI); |
| 58 | 59 | ToHeader toHeader = layer.getHeaderFactory().createToHeader(toAddress, toTag); |
| 59 | 60 | // callid |
| ... | ... | @@ -71,6 +72,49 @@ public class SIPRequestHeaderProvider { |
| 71 | 72 | return request; |
| 72 | 73 | } |
| 73 | 74 | |
| 75 | +// public Request createInviteRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException { | |
| 76 | +// Request request = null; | |
| 77 | +// Host host = device.getHost(); | |
| 78 | +// //请求行 | |
| 79 | +// SipURI requestLine = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); | |
| 80 | +// //via | |
| 81 | +// ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 82 | +// ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag); | |
| 83 | +// viaHeader.setRPort(); | |
| 84 | +// viaHeaders.add(viaHeader); | |
| 85 | +// //from | |
| 86 | +// SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),sipConfig.getSipIp()+":"+sipConfig.getSipPort()); | |
| 87 | +// Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI); | |
| 88 | +// FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack | |
| 89 | +// //to | |
| 90 | +// SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),host.getAddress()); | |
| 91 | +// Address toAddress = layer.getAddressFactory().createAddress(toSipURI); | |
| 92 | +// ToHeader toHeader = layer.getHeaderFactory().createToHeader(toAddress,null); | |
| 93 | +// | |
| 94 | +// //callid | |
| 95 | +// CallIdHeader callIdHeader = null; | |
| 96 | +// if(device.getTransport().equals("TCP")) { | |
| 97 | +// callIdHeader = layer.getTcpSipProvider().getNewCallId(); | |
| 98 | +// } | |
| 99 | +// if(device.getTransport().equals("UDP")) { | |
| 100 | +// callIdHeader = layer.getUdpSipProvider().getNewCallId(); | |
| 101 | +// } | |
| 102 | +// | |
| 103 | +// //Forwards | |
| 104 | +// MaxForwardsHeader maxForwards = layer.getHeaderFactory().createMaxForwardsHeader(70); | |
| 105 | +// | |
| 106 | +// //ceq | |
| 107 | +// CSeqHeader cSeqHeader = layer.getHeaderFactory().createCSeqHeader(1L, Request.INVITE); | |
| 108 | +// request = layer.getMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); | |
| 109 | +// | |
| 110 | +// Address concatAddress = layer.getAddressFactory().createAddress(layer.getAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); | |
| 111 | +// request.addHeader(layer.getHeaderFactory().createContactHeader(concatAddress)); | |
| 112 | +// | |
| 113 | +// ContentTypeHeader contentTypeHeader = layer.getHeaderFactory().createContentTypeHeader("Application", "SDP"); | |
| 114 | +// request.setContent(content, contentTypeHeader); | |
| 115 | +// return request; | |
| 116 | +// } | |
| 117 | + | |
| 74 | 118 | public Request createInviteRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException { |
| 75 | 119 | Request request = null; |
| 76 | 120 | Host host = device.getHost(); |
| ... | ... | @@ -82,11 +126,11 @@ public class SIPRequestHeaderProvider { |
| 82 | 126 | viaHeader.setRPort(); |
| 83 | 127 | viaHeaders.add(viaHeader); |
| 84 | 128 | //from |
| 85 | - SipURI fromSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),sipConfig.getSipIp()+":"+sipConfig.getSipPort()); | |
| 129 | + SipURI fromSipURI = layer.getAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain()); | |
| 86 | 130 | Address fromAddress = layer.getAddressFactory().createAddress(fromSipURI); |
| 87 | 131 | FromHeader fromHeader = layer.getHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack |
| 88 | 132 | //to |
| 89 | - SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),host.getAddress()); | |
| 133 | + SipURI toSipURI = layer.getAddressFactory().createSipURI(device.getDeviceId(),sipConfig.getSipDomain()); | |
| 90 | 134 | Address toAddress = layer.getAddressFactory().createAddress(toSipURI); |
| 91 | 135 | ToHeader toHeader = layer.getHeaderFactory().createToHeader(toAddress,null); |
| 92 | 136 | |
| ... | ... | @@ -101,9 +145,14 @@ public class SIPRequestHeaderProvider { |
| 101 | 145 | |
| 102 | 146 | //Forwards |
| 103 | 147 | MaxForwardsHeader maxForwards = layer.getHeaderFactory().createMaxForwardsHeader(70); |
| 148 | + | |
| 104 | 149 | //ceq |
| 105 | 150 | CSeqHeader cSeqHeader = layer.getHeaderFactory().createCSeqHeader(1L, Request.INVITE); |
| 106 | 151 | request = layer.getMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); |
| 152 | + | |
| 153 | + Address concatAddress = layer.getAddressFactory().createAddress(layer.getAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); | |
| 154 | + request.addHeader(layer.getHeaderFactory().createContactHeader(concatAddress)); | |
| 155 | + | |
| 107 | 156 | ContentTypeHeader contentTypeHeader = layer.getHeaderFactory().createContentTypeHeader("Application", "SDP"); |
| 108 | 157 | request.setContent(content, contentTypeHeader); |
| 109 | 158 | return request; | ... | ... |
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; |
| 3 | 3 | import java.text.ParseException; |
| 4 | 4 | |
| 5 | 5 | import javax.sip.ClientTransaction; |
| 6 | +import javax.sip.Dialog; | |
| 6 | 7 | import javax.sip.InvalidArgumentException; |
| 7 | 8 | import javax.sip.SipException; |
| 9 | +import javax.sip.TransactionDoesNotExistException; | |
| 10 | +import javax.sip.header.ViaHeader; | |
| 8 | 11 | import javax.sip.message.Request; |
| 9 | 12 | |
| 10 | 13 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -13,10 +16,10 @@ import org.springframework.stereotype.Component; |
| 13 | 16 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 14 | 17 | import com.genersoft.iot.vmp.gb28181.SipLayer; |
| 15 | 18 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 19 | +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 16 | 20 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 17 | 21 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; |
| 18 | 22 | import com.genersoft.iot.vmp.gb28181.utils.DateUtil; |
| 19 | -import com.genersoft.iot.vmp.gb28181.utils.SsrcUtil; | |
| 20 | 23 | |
| 21 | 24 | /** |
| 22 | 25 | * @Description:设备能力接口,用于定义设备的控制、查询能力 |
| ... | ... | @@ -35,6 +38,9 @@ public class SIPCommander implements ISIPCommander { |
| 35 | 38 | @Autowired |
| 36 | 39 | private SipLayer sipLayer; |
| 37 | 40 | |
| 41 | + @Autowired | |
| 42 | + private VideoStreamSessionManager streamSession; | |
| 43 | + | |
| 38 | 44 | /** |
| 39 | 45 | * 云台方向放控制,使用配置文件中的默认镜头移动速度 |
| 40 | 46 | * |
| ... | ... | @@ -135,11 +141,11 @@ public class SIPCommander implements ISIPCommander { |
| 135 | 141 | public String playStreamCmd(Device device, String channelId) { |
| 136 | 142 | try { |
| 137 | 143 | |
| 138 | - String ssrc = SsrcUtil.getPlaySsrc(); | |
| 144 | + String ssrc = streamSession.createPlaySsrc(); | |
| 139 | 145 | // |
| 140 | 146 | StringBuffer content = new StringBuffer(200); |
| 141 | 147 | content.append("v=0\r\n"); |
| 142 | - content.append("o="+channelId+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n"); | |
| 148 | + content.append("o="+channelId+" 0 0 IN IP4 "+sipConfig.getMediaIp()+"\r\n"); | |
| 143 | 149 | content.append("s=Play\r\n"); |
| 144 | 150 | content.append("c=IN IP4 "+sipConfig.getMediaIp()+"\r\n"); |
| 145 | 151 | content.append("t=0 0\r\n"); |
| ... | ... | @@ -161,7 +167,8 @@ public class SIPCommander implements ISIPCommander { |
| 161 | 167 | |
| 162 | 168 | Request request = headerProvider.createInviteRequest(device, content.toString(), null, "live", null); |
| 163 | 169 | |
| 164 | - transmitRequest(device, request); | |
| 170 | + ClientTransaction transaction = transmitRequest(device, request); | |
| 171 | + streamSession.put(ssrc, transaction); | |
| 165 | 172 | return ssrc; |
| 166 | 173 | } catch ( SipException | ParseException | InvalidArgumentException e) { |
| 167 | 174 | e.printStackTrace(); |
| ... | ... | @@ -181,11 +188,11 @@ public class SIPCommander implements ISIPCommander { |
| 181 | 188 | public String playbackStreamCmd(Device device, String channelId, String startTime, String endTime) { |
| 182 | 189 | try { |
| 183 | 190 | |
| 184 | - String ssrc = SsrcUtil.getPlayBackSsrc(); | |
| 191 | + String ssrc = streamSession.createPlayBackSsrc(); | |
| 185 | 192 | // |
| 186 | 193 | StringBuffer content = new StringBuffer(200); |
| 187 | 194 | content.append("v=0\r\n"); |
| 188 | - content.append("o="+device.getDeviceId()+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n"); | |
| 195 | + content.append("o="+device.getDeviceId()+" 0 0 IN IP4 "+sipConfig.getMediaIp()+"\r\n"); | |
| 189 | 196 | content.append("s=Playback\r\n"); |
| 190 | 197 | content.append("u="+channelId+":3\r\n"); |
| 191 | 198 | content.append("c=IN IP4 "+sipConfig.getMediaIp()+"\r\n"); |
| ... | ... | @@ -208,13 +215,50 @@ public class SIPCommander implements ISIPCommander { |
| 208 | 215 | |
| 209 | 216 | Request request = headerProvider.createInviteRequest(device, content.toString(), null, "live", null); |
| 210 | 217 | |
| 211 | - transmitRequest(device, request); | |
| 218 | + ClientTransaction transaction = transmitRequest(device, request); | |
| 219 | + streamSession.put(ssrc, transaction); | |
| 212 | 220 | return ssrc; |
| 213 | 221 | } catch ( SipException | ParseException | InvalidArgumentException e) { |
| 214 | 222 | e.printStackTrace(); |
| 215 | 223 | return null; |
| 216 | 224 | } |
| 217 | 225 | } |
| 226 | + | |
| 227 | + /** | |
| 228 | + * 视频流停止 | |
| 229 | + * | |
| 230 | + * @param device 视频设备 | |
| 231 | + * @param channelId 预览通道 | |
| 232 | + */ | |
| 233 | + @Override | |
| 234 | + public void streamByeCmd(String ssrc) { | |
| 235 | + | |
| 236 | + try { | |
| 237 | + ClientTransaction transaction = streamSession.get(ssrc); | |
| 238 | + if (transaction == null) { | |
| 239 | + return; | |
| 240 | + } | |
| 241 | + | |
| 242 | + Dialog dialog = transaction.getDialog(); | |
| 243 | + if (dialog == null) { | |
| 244 | + return; | |
| 245 | + } | |
| 246 | + Request byeRequest = dialog.createRequest(Request.BYE); | |
| 247 | + ViaHeader viaHeader = (ViaHeader) byeRequest.getHeader(ViaHeader.NAME); | |
| 248 | + String protocol = viaHeader.getTransport(); | |
| 249 | + ClientTransaction clientTransaction = null; | |
| 250 | + if("TCP".equals(protocol)) { | |
| 251 | + clientTransaction = sipLayer.getTcpSipProvider().getNewClientTransaction(byeRequest); | |
| 252 | + } else if("UDP".equals(protocol)) { | |
| 253 | + clientTransaction = sipLayer.getUdpSipProvider().getNewClientTransaction(byeRequest); | |
| 254 | + } | |
| 255 | + dialog.sendRequest(clientTransaction); | |
| 256 | + } catch (TransactionDoesNotExistException e) { | |
| 257 | + e.printStackTrace(); | |
| 258 | + } catch (SipException e) { | |
| 259 | + e.printStackTrace(); | |
| 260 | + } | |
| 261 | + } | |
| 218 | 262 | |
| 219 | 263 | /** |
| 220 | 264 | * 语音广播 |
| ... | ... | @@ -435,16 +479,15 @@ public class SIPCommander implements ISIPCommander { |
| 435 | 479 | return false; |
| 436 | 480 | } |
| 437 | 481 | |
| 438 | - private void transmitRequest(Device device, Request request) throws SipException { | |
| 482 | + private ClientTransaction transmitRequest(Device device, Request request) throws SipException { | |
| 439 | 483 | ClientTransaction clientTransaction = null; |
| 440 | - if(device.getTransport().equals("TCP")) { | |
| 484 | + if("TCP".equals(device.getTransport())) { | |
| 441 | 485 | clientTransaction = sipLayer.getTcpSipProvider().getNewClientTransaction(request); |
| 442 | - //sipLayer.getTcpSipProvider().sendRequest(request); | |
| 443 | - } else if(device.getTransport().equals("UDP")) { | |
| 486 | + } else if("UDP".equals(device.getTransport())) { | |
| 444 | 487 | clientTransaction = sipLayer.getUdpSipProvider().getNewClientTransaction(request); |
| 445 | - //sipLayer.getUdpSipProvider().sendRequest(request); | |
| 446 | 488 | } |
| 447 | 489 | clientTransaction.sendRequest(); |
| 490 | + return clientTransaction; | |
| 448 | 491 | } |
| 449 | 492 | |
| 450 | 493 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/ISIPRequestProcessor.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.transmit.request; |
| 2 | 2 | |
| 3 | 3 | import javax.sip.RequestEvent; |
| 4 | -import javax.sip.ServerTransaction; | |
| 5 | 4 | |
| 6 | 5 | import com.genersoft.iot.vmp.gb28181.SipLayer; |
| 7 | 6 | |
| ... | ... | @@ -12,6 +11,6 @@ import com.genersoft.iot.vmp.gb28181.SipLayer; |
| 12 | 11 | */ |
| 13 | 12 | public interface ISIPRequestProcessor { |
| 14 | 13 | |
| 15 | - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction); | |
| 14 | + public void process(RequestEvent evt, SipLayer layer); | |
| 16 | 15 | |
| 17 | 16 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java
| ... | ... | @@ -31,7 +31,7 @@ public class AckRequestProcessor implements ISIPRequestProcessor { |
| 31 | 31 | * @param config |
| 32 | 32 | */ |
| 33 | 33 | @Override |
| 34 | - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { | |
| 34 | + public void process(RequestEvent evt, SipLayer layer) { | |
| 35 | 35 | Request request = evt.getRequest(); |
| 36 | 36 | Dialog dialog = evt.getDialog(); |
| 37 | 37 | try { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java
| ... | ... | @@ -25,7 +25,7 @@ public class ByeRequestProcessor implements ISIPRequestProcessor { |
| 25 | 25 | * @param config |
| 26 | 26 | */ |
| 27 | 27 | @Override |
| 28 | - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { | |
| 28 | + public void process(RequestEvent evt, SipLayer layer) { | |
| 29 | 29 | // TODO Auto-generated method stub |
| 30 | 30 | |
| 31 | 31 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/CancelRequestProcessor.java
| ... | ... | @@ -25,7 +25,7 @@ public class CancelRequestProcessor implements ISIPRequestProcessor { |
| 25 | 25 | * @param config |
| 26 | 26 | */ |
| 27 | 27 | @Override |
| 28 | - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { | |
| 28 | + public void process(RequestEvent evt, SipLayer layer) { | |
| 29 | 29 | // TODO Auto-generated method stub |
| 30 | 30 | |
| 31 | 31 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
| ... | ... | @@ -23,7 +23,7 @@ public class InviteRequestProcessor implements ISIPRequestProcessor { |
| 23 | 23 | * 请求消息 |
| 24 | 24 | */ |
| 25 | 25 | @Override |
| 26 | - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { | |
| 26 | + public void process(RequestEvent evt, SipLayer layer) { | |
| 27 | 27 | // TODO Auto-generated method stub |
| 28 | 28 | // Request request = requestEvent.getRequest(); |
| 29 | 29 | // | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
| ... | ... | @@ -93,10 +93,10 @@ public class MessageRequestProcessor implements ISIPRequestProcessor { |
| 93 | 93 | * @param transaction |
| 94 | 94 | */ |
| 95 | 95 | @Override |
| 96 | - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { | |
| 96 | + public void process(RequestEvent evt, SipLayer layer) { | |
| 97 | 97 | |
| 98 | 98 | this.layer = layer; |
| 99 | - this.transaction = transaction; | |
| 99 | + this.transaction = layer.getServerTransaction(evt); | |
| 100 | 100 | |
| 101 | 101 | Request request = evt.getRequest(); |
| 102 | 102 | SAXReader reader = new SAXReader(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/OtherRequestProcessor.java
| ... | ... | @@ -25,7 +25,7 @@ public class OtherRequestProcessor implements ISIPRequestProcessor { |
| 25 | 25 | * @param config |
| 26 | 26 | */ |
| 27 | 27 | @Override |
| 28 | - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { | |
| 28 | + public void process(RequestEvent evt, SipLayer layer) { | |
| 29 | 29 | System.out.println("no support the method! Method:" + evt.getRequest().getMethod()); |
| 30 | 30 | } |
| 31 | 31 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java
| ... | ... | @@ -63,7 +63,7 @@ public class RegisterRequestProcessor implements ISIPRequestProcessor { |
| 63 | 63 | * 请求消息 |
| 64 | 64 | */ |
| 65 | 65 | @Override |
| 66 | - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { | |
| 66 | + public void process(RequestEvent evt, SipLayer layer) { | |
| 67 | 67 | try { |
| 68 | 68 | System.out.println("收到注册请求,开始处理"); |
| 69 | 69 | Request request = evt.getRequest(); |
| ... | ... | @@ -141,7 +141,7 @@ public class RegisterRequestProcessor implements ISIPRequestProcessor { |
| 141 | 141 | device.setTransport(isTcp ? "TCP" : "UDP"); |
| 142 | 142 | } |
| 143 | 143 | } |
| 144 | - transaction.sendResponse(response); | |
| 144 | + layer.getServerTransaction(evt).sendResponse(response); | |
| 145 | 145 | // 注册成功 |
| 146 | 146 | // 保存到redis |
| 147 | 147 | // 下发catelog查询目录 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java
| ... | ... | @@ -32,7 +32,7 @@ public class SubscribeRequestProcessor implements ISIPRequestProcessor { |
| 32 | 32 | * @param config |
| 33 | 33 | */ |
| 34 | 34 | @Override |
| 35 | - public void process(RequestEvent evt, SipLayer layer, ServerTransaction transaction) { | |
| 35 | + public void process(RequestEvent evt, SipLayer layer) { | |
| 36 | 36 | Request request = evt.getRequest(); |
| 37 | 37 | |
| 38 | 38 | try { |
| ... | ... | @@ -43,7 +43,7 @@ public class SubscribeRequestProcessor implements ISIPRequestProcessor { |
| 43 | 43 | response.setExpires(expireHeader); |
| 44 | 44 | } |
| 45 | 45 | System.out.println("response : " + response.toString()); |
| 46 | - | |
| 46 | + ServerTransaction transaction = layer.getServerTransaction(evt); | |
| 47 | 47 | if (transaction != null) { |
| 48 | 48 | transaction.sendResponse(response); |
| 49 | 49 | transaction.terminate(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java
| ... | ... | @@ -50,31 +50,33 @@ public class InviteResponseProcessor implements ISIPResponseProcessor { |
| 50 | 50 | //成功响应 |
| 51 | 51 | //下发ack |
| 52 | 52 | if(statusCode == Response.OK){ |
| 53 | - ClientTransaction clientTransaction = evt.getClientTransaction(); | |
| 54 | - if(clientTransaction == null){ | |
| 55 | - logger.error("回复ACK时,clientTransaction为null >>> {}",response); | |
| 56 | - return; | |
| 57 | - } | |
| 58 | - Dialog clientDialog = clientTransaction.getDialog(); | |
| 59 | - | |
| 60 | - CSeqHeader clientCSeqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME); | |
| 61 | - long cseqId = clientCSeqHeader.getSeqNumber(); | |
| 62 | - /* | |
| 63 | - createAck函数,创建的ackRequest,会采用Invite响应的200OK,中的contact字段中的地址,作为目标地址。 | |
| 64 | - 有的终端传上来的可能还是内网地址,会造成ack发送不出去。接受不到音视频流 | |
| 65 | - 所以在此处统一替换地址。和响应消息的Via头中的地址保持一致。 | |
| 66 | - */ | |
| 67 | - Request ackRequest = clientDialog.createAck(cseqId); | |
| 68 | - SipURI requestURI = (SipURI) ackRequest.getRequestURI(); | |
| 69 | - ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME); | |
| 70 | - requestURI.setHost(viaHeader.getHost()); | |
| 71 | - requestURI.setPort(viaHeader.getPort()); | |
| 72 | - clientDialog.sendAck(ackRequest); | |
| 53 | +// ClientTransaction clientTransaction = evt.getClientTransaction(); | |
| 54 | +// if(clientTransaction == null){ | |
| 55 | +// logger.error("回复ACK时,clientTransaction为null >>> {}",response); | |
| 56 | +// return; | |
| 57 | +// } | |
| 58 | +// Dialog clientDialog = clientTransaction.getDialog(); | |
| 59 | +// | |
| 60 | +// CSeqHeader clientCSeqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME); | |
| 61 | +// long cseqId = clientCSeqHeader.getSeqNumber(); | |
| 62 | +// /* | |
| 63 | +// createAck函数,创建的ackRequest,会采用Invite响应的200OK,中的contact字段中的地址,作为目标地址。 | |
| 64 | +// 有的终端传上来的可能还是内网地址,会造成ack发送不出去。接受不到音视频流 | |
| 65 | +// 所以在此处统一替换地址。和响应消息的Via头中的地址保持一致。 | |
| 66 | +// */ | |
| 67 | +// Request ackRequest = clientDialog.createAck(cseqId); | |
| 68 | +// SipURI requestURI = (SipURI) ackRequest.getRequestURI(); | |
| 69 | +// ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME); | |
| 70 | +// requestURI.setHost(viaHeader.getHost()); | |
| 71 | +// requestURI.setPort(viaHeader.getPort()); | |
| 72 | +// clientDialog.sendAck(ackRequest); | |
| 73 | + | |
| 74 | + Dialog dialog = evt.getDialog(); | |
| 75 | + Request reqAck =dialog.createAck(1L); | |
| 76 | + dialog.sendAck(reqAck); | |
| 73 | 77 | } |
| 74 | 78 | } catch (InvalidArgumentException | SipException e) { |
| 75 | 79 | e.printStackTrace(); |
| 76 | - } catch (ParseException e) { | |
| 77 | - e.printStackTrace(); | |
| 78 | 80 | } |
| 79 | 81 | } |
| 80 | 82 | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
| ... | ... | @@ -96,8 +96,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { |
| 96 | 96 | */ |
| 97 | 97 | @Override |
| 98 | 98 | public boolean delete(String deviceId) { |
| 99 | - redis.del(VideoManagerConstants.CACHEKEY_PREFIX+deviceId); | |
| 100 | - return true; | |
| 99 | + return redis.del(VideoManagerConstants.CACHEKEY_PREFIX+deviceId); | |
| 101 | 100 | } |
| 102 | 101 | |
| 103 | 102 | /** | ... | ... |
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
| ... | ... | @@ -68,14 +68,20 @@ public class RedisUtil { |
| 68 | 68 | * @SuppressWarnings("unchecked") 忽略类型转换警告 |
| 69 | 69 | * @param key 键(一个或者多个) |
| 70 | 70 | */ |
| 71 | - public void del(String... key) { | |
| 72 | - if (key != null && key.length > 0) { | |
| 73 | - if (key.length == 1) { | |
| 74 | - redisTemplate.delete(key[0]); | |
| 75 | - } else { | |
| 76 | -// 传入一个 Collection<String> 集合 | |
| 77 | - redisTemplate.delete(CollectionUtils.arrayToList(key)); | |
| 71 | + public boolean del(String... key) { | |
| 72 | + try { | |
| 73 | + if (key != null && key.length > 0) { | |
| 74 | + if (key.length == 1) { | |
| 75 | + redisTemplate.delete(key[0]); | |
| 76 | + } else { | |
| 77 | +// 传入一个 Collection<String> 集合 | |
| 78 | + redisTemplate.delete(CollectionUtils.arrayToList(key)); | |
| 79 | + } | |
| 78 | 80 | } |
| 81 | + return true; | |
| 82 | + } catch (Exception e) { | |
| 83 | + e.printStackTrace(); | |
| 84 | + return false; | |
| 79 | 85 | } |
| 80 | 86 | } |
| 81 | 87 | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java
| ... | ... | @@ -14,7 +14,9 @@ import org.springframework.web.bind.annotation.RequestMapping; |
| 14 | 14 | import org.springframework.web.bind.annotation.RestController; |
| 15 | 15 | import org.springframework.web.context.request.async.DeferredResult; |
| 16 | 16 | |
| 17 | +import com.alibaba.fastjson.JSONObject; | |
| 17 | 18 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 19 | +import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; | |
| 18 | 20 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 19 | 21 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 20 | 22 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| ... | ... | @@ -34,6 +36,9 @@ public class DeviceController { |
| 34 | 36 | @Autowired |
| 35 | 37 | private DeferredResultHolder resultHolder; |
| 36 | 38 | |
| 39 | + @Autowired | |
| 40 | + private DeviceOffLineDetector offLineDetector; | |
| 41 | + | |
| 37 | 42 | @GetMapping("/devices/{deviceId}") |
| 38 | 43 | public ResponseEntity<Device> devices(@PathVariable String deviceId){ |
| 39 | 44 | |
| ... | ... | @@ -69,4 +74,25 @@ public class DeviceController { |
| 69 | 74 | resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result); |
| 70 | 75 | return result; |
| 71 | 76 | } |
| 77 | + | |
| 78 | + @PostMapping("/devices/{deviceId}/delete") | |
| 79 | + public ResponseEntity<String> delete(@PathVariable String deviceId){ | |
| 80 | + | |
| 81 | + if (logger.isDebugEnabled()) { | |
| 82 | + logger.debug("设备信息删除API调用,deviceId:" + deviceId); | |
| 83 | + } | |
| 84 | + | |
| 85 | + if (offLineDetector.isOnline(deviceId)) { | |
| 86 | + return new ResponseEntity<String>("不允许删除在线设备!", HttpStatus.NOT_ACCEPTABLE); | |
| 87 | + } | |
| 88 | + boolean isSuccess = storager.delete(deviceId); | |
| 89 | + if (isSuccess) { | |
| 90 | + JSONObject json = new JSONObject(); | |
| 91 | + json.put("deviceId", deviceId); | |
| 92 | + return new ResponseEntity<>(json.toString(),HttpStatus.OK); | |
| 93 | + } else { | |
| 94 | + logger.warn("设备预览API调用失败!"); | |
| 95 | + return new ResponseEntity<String>("设备预览API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); | |
| 96 | + } | |
| 97 | + } | |
| 72 | 98 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
| ... | ... | @@ -7,6 +7,7 @@ import org.springframework.http.HttpStatus; |
| 7 | 7 | import org.springframework.http.ResponseEntity; |
| 8 | 8 | import org.springframework.web.bind.annotation.GetMapping; |
| 9 | 9 | import org.springframework.web.bind.annotation.PathVariable; |
| 10 | +import org.springframework.web.bind.annotation.PostMapping; | |
| 10 | 11 | import org.springframework.web.bind.annotation.RequestMapping; |
| 11 | 12 | import org.springframework.web.bind.annotation.RestController; |
| 12 | 13 | |
| ... | ... | @@ -47,4 +48,23 @@ public class PlayController { |
| 47 | 48 | return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR); |
| 48 | 49 | } |
| 49 | 50 | } |
| 51 | + | |
| 52 | + @PostMapping("/play/{ssrc}/stop") | |
| 53 | + public ResponseEntity<String> playStop(@PathVariable String ssrc){ | |
| 54 | + | |
| 55 | + cmder.streamByeCmd(ssrc); | |
| 56 | + | |
| 57 | + if (logger.isDebugEnabled()) { | |
| 58 | + logger.debug(String.format("设备预览停止API调用,ssrc:%s", ssrc)); | |
| 59 | + } | |
| 60 | + | |
| 61 | + if(ssrc!=null) { | |
| 62 | + JSONObject json = new JSONObject(); | |
| 63 | + json.put("ssrc", ssrc); | |
| 64 | + return new ResponseEntity<String>(json.toString(),HttpStatus.OK); | |
| 65 | + } else { | |
| 66 | + logger.warn("设备预览停止API调用失败!"); | |
| 67 | + return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR); | |
| 68 | + } | |
| 69 | + } | |
| 50 | 70 | } | ... | ... |
src/main/resources/application.yml