Commit c041aaccb43baf73d1a9f5b50fb5a1f410b88523
1 parent
2591997d
修复录像回放中的信令错误
Showing
10 changed files
with
177 additions
and
99 deletions
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| ... | ... | @@ -77,38 +77,54 @@ public class VideoManagerConstants { |
| 77 | 77 | |
| 78 | 78 | //************************** redis 消息********************************* |
| 79 | 79 | |
| 80 | - // 流变化的通知 | |
| 80 | + /** | |
| 81 | + * 流变化的通知 | |
| 82 | + */ | |
| 81 | 83 | public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_"; |
| 82 | 84 | |
| 83 | - // 接收推流设备的GPS变化通知 | |
| 85 | + /** | |
| 86 | + * 接收推流设备的GPS变化通知 | |
| 87 | + */ | |
| 84 | 88 | public static final String VM_MSG_GPS = "VM_MSG_GPS"; |
| 85 | 89 | |
| 86 | - // 接收推流设备的GPS变化通知 | |
| 90 | + /** | |
| 91 | + * 接收推流设备的GPS变化通知 | |
| 92 | + */ | |
| 87 | 93 | public static final String VM_MSG_PUSH_STREAM_STATUS_CHANGE = "VM_MSG_PUSH_STREAM_STATUS_CHANGE"; |
| 88 | 94 | |
| 89 | - // redis 消息通知设备推流到平台 | |
| 95 | + /** | |
| 96 | + * redis 消息通知设备推流到平台 | |
| 97 | + */ | |
| 90 | 98 | public static final String VM_MSG_STREAM_PUSH_REQUESTED = "VM_MSG_STREAM_PUSH_REQUESTED"; |
| 91 | 99 | |
| 92 | - // redis 消息请求所有的在线通道 | |
| 100 | + /** | |
| 101 | + * redis 消息请求所有的在线通道 | |
| 102 | + */ | |
| 93 | 103 | public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED"; |
| 94 | 104 | |
| 95 | - // 移动位置订阅通知 | |
| 105 | + /** | |
| 106 | + * 移动位置订阅通知 | |
| 107 | + */ | |
| 96 | 108 | public static final String VM_MSG_SUBSCRIBE_MOBILE_POSITION = "mobileposition"; |
| 97 | 109 | |
| 98 | - // 报警订阅的通知(收到报警向redis发出通知) | |
| 110 | + /** | |
| 111 | + * 报警订阅的通知(收到报警向redis发出通知) | |
| 112 | + */ | |
| 99 | 113 | public static final String VM_MSG_SUBSCRIBE_ALARM = "alarm"; |
| 100 | 114 | |
| 101 | - // 报警通知的发送 (收到redis发出的通知,转发给其他平台) | |
| 115 | + /** | |
| 116 | + * 报警通知的发送 (收到redis发出的通知,转发给其他平台) | |
| 117 | + */ | |
| 102 | 118 | public static final String VM_MSG_SUBSCRIBE_ALARM_RECEIVE= "alarm_receive"; |
| 103 | 119 | |
| 104 | - // 设备状态订阅的通知 | |
| 120 | + /** | |
| 121 | + * 设备状态订阅的通知 | |
| 122 | + */ | |
| 105 | 123 | public static final String VM_MSG_SUBSCRIBE_DEVICE_STATUS = "device"; |
| 106 | 124 | |
| 107 | 125 | |
| 108 | - | |
| 109 | - | |
| 110 | - | |
| 111 | 126 | //************************** 第三方 **************************************** |
| 127 | + | |
| 112 | 128 | public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; |
| 113 | 129 | public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; |
| 114 | 130 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
| ... | ... | @@ -62,7 +62,7 @@ public class SIPRequestHeaderPlarformProvider { |
| 62 | 62 | // Forwards |
| 63 | 63 | MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
| 64 | 64 | // ceq |
| 65 | - CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(Request.MESSAGE), Request.MESSAGE); | |
| 65 | + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE); | |
| 66 | 66 | |
| 67 | 67 | request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, |
| 68 | 68 | toHeader, viaHeaders, maxForwards); |
| ... | ... | @@ -120,7 +120,7 @@ public class SIPRequestHeaderPlarformProvider { |
| 120 | 120 | String callId, WWWAuthenticateHeader www , CallIdHeader callIdHeader) throws ParseException, PeerUnavailableException, InvalidArgumentException { |
| 121 | 121 | |
| 122 | 122 | |
| 123 | - Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(Request.REGISTER), fromTag, viaTag, callIdHeader); | |
| 123 | + Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(), fromTag, viaTag, callIdHeader); | |
| 124 | 124 | SipURI requestURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort()); |
| 125 | 125 | if (www == null) { |
| 126 | 126 | AuthorizationHeader authorizationHeader = sipFactory.createHeaderFactory().createAuthorizationHeader("Digest"); |
| ... | ... | @@ -213,7 +213,7 @@ public class SIPRequestHeaderPlarformProvider { |
| 213 | 213 | // Forwards |
| 214 | 214 | MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
| 215 | 215 | // ceq |
| 216 | - CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(Request.MESSAGE), Request.MESSAGE); | |
| 216 | + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE); | |
| 217 | 217 | MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory(); |
| 218 | 218 | // 设置编码, 防止中文乱码 |
| 219 | 219 | messageFactory.setDefaultContentEncodingCharset(parentPlatform.getCharacterSet()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
| ... | ... | @@ -2,11 +2,9 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd; |
| 2 | 2 | |
| 3 | 3 | import java.text.ParseException; |
| 4 | 4 | import java.util.ArrayList; |
| 5 | +import java.util.List; | |
| 5 | 6 | |
| 6 | -import javax.sip.Dialog; | |
| 7 | -import javax.sip.InvalidArgumentException; | |
| 8 | -import javax.sip.PeerUnavailableException; | |
| 9 | -import javax.sip.SipFactory; | |
| 7 | +import javax.sip.*; | |
| 10 | 8 | import javax.sip.address.Address; |
| 11 | 9 | import javax.sip.address.SipURI; |
| 12 | 10 | import javax.sip.header.*; |
| ... | ... | @@ -15,7 +13,11 @@ import javax.sip.message.Request; |
| 15 | 13 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 16 | 14 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| 17 | 15 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 16 | +import gov.nist.javax.sip.SipProviderImpl; | |
| 17 | +import gov.nist.javax.sip.SipStackImpl; | |
| 18 | +import gov.nist.javax.sip.stack.SIPDialog; | |
| 18 | 19 | import org.springframework.beans.factory.annotation.Autowired; |
| 20 | +import org.springframework.beans.factory.annotation.Qualifier; | |
| 19 | 21 | import org.springframework.stereotype.Component; |
| 20 | 22 | |
| 21 | 23 | import com.genersoft.iot.vmp.conf.SipConfig; |
| ... | ... | @@ -40,6 +42,14 @@ public class SIPRequestHeaderProvider { |
| 40 | 42 | |
| 41 | 43 | @Autowired |
| 42 | 44 | private VideoStreamSessionManager streamSession; |
| 45 | + | |
| 46 | + @Autowired | |
| 47 | + @Qualifier(value="tcpSipProvider") | |
| 48 | + private SipProviderImpl tcpSipProvider; | |
| 49 | + | |
| 50 | + @Autowired | |
| 51 | + @Qualifier(value="udpSipProvider") | |
| 52 | + private SipProviderImpl udpSipProvider; | |
| 43 | 53 | |
| 44 | 54 | public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { |
| 45 | 55 | Request request = null; |
| ... | ... | @@ -95,7 +105,7 @@ public class SIPRequestHeaderProvider { |
| 95 | 105 | MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
| 96 | 106 | |
| 97 | 107 | //ceq |
| 98 | - CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(Request.INVITE), Request.INVITE); | |
| 108 | + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); | |
| 99 | 109 | request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); |
| 100 | 110 | |
| 101 | 111 | Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort())); |
| ... | ... | @@ -131,7 +141,7 @@ public class SIPRequestHeaderProvider { |
| 131 | 141 | MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
| 132 | 142 | |
| 133 | 143 | //ceq |
| 134 | - CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(Request.INVITE), Request.INVITE); | |
| 144 | + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); | |
| 135 | 145 | request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); |
| 136 | 146 | |
| 137 | 147 | Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort())); |
| ... | ... | @@ -200,7 +210,7 @@ public class SIPRequestHeaderProvider { |
| 200 | 210 | MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); |
| 201 | 211 | |
| 202 | 212 | // ceq |
| 203 | - CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(Request.SUBSCRIBE), Request.SUBSCRIBE); | |
| 213 | + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.SUBSCRIBE); | |
| 204 | 214 | |
| 205 | 215 | request = sipFactory.createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader, |
| 206 | 216 | toHeader, viaHeaders, maxForwards); |
| ... | ... | @@ -226,55 +236,55 @@ public class SIPRequestHeaderProvider { |
| 226 | 236 | } |
| 227 | 237 | |
| 228 | 238 | public Request createInfoRequest(Device device, StreamInfo streamInfo, String content) |
| 229 | - throws PeerUnavailableException, ParseException, InvalidArgumentException { | |
| 230 | - Request request = null; | |
| 239 | + throws SipException, ParseException, InvalidArgumentException { | |
| 231 | 240 | if (streamInfo == null) { |
| 232 | 241 | return null; |
| 233 | 242 | } |
| 234 | - Dialog dialog = streamSession.getDialogByStream(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream()); | |
| 243 | + Request request = null; | |
| 244 | + SIPDialog dialog = streamSession.getDialogByStream(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream()); | |
| 235 | 245 | if (dialog == null) { |
| 236 | 246 | return null; |
| 237 | 247 | } |
| 238 | 248 | |
| 239 | - SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), | |
| 240 | - device.getHostAddress()); | |
| 241 | - // via | |
| 242 | - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | |
| 243 | - ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), | |
| 244 | - device.getTransport(), null); | |
| 249 | + SipStack sipStack = udpSipProvider.getSipStack(); | |
| 250 | + SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog); | |
| 251 | + if (dialog != sipDialog) { | |
| 252 | + dialog = sipDialog; | |
| 253 | + }else { | |
| 254 | + dialog.setSipProvider(udpSipProvider); | |
| 255 | + } | |
| 256 | + streamSession.put(streamInfo.getDeviceID(), streamInfo.getChannelId(), dialog.getCallId().getCallId(), dialog); | |
| 257 | + Request infoRequest = dialog.createRequest(Request.INFO); | |
| 258 | + SipURI sipURI = (SipURI) infoRequest.getRequestURI(); | |
| 259 | + sipURI.setHost(device.getIp()); | |
| 260 | + sipURI.setPort(device.getPort()); | |
| 261 | + sipURI.setUser(streamInfo.getChannelId()); | |
| 262 | + | |
| 263 | + ViaHeader viaHeader = (ViaHeader) infoRequest.getHeader(ViaHeader.NAME); | |
| 245 | 264 | viaHeader.setRPort(); |
| 246 | - viaHeaders.add(viaHeader); | |
| 247 | - // from | |
| 248 | - SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), | |
| 249 | - sipConfig.getDomain()); | |
| 250 | - Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI); | |
| 251 | - FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, dialog.getLocalTag()); | |
| 252 | - // to | |
| 253 | - SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(streamInfo.getChannelId(), | |
| 254 | - sipConfig.getDomain()); | |
| 255 | - Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI); | |
| 256 | - ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, dialog.getRemoteTag()); | |
| 257 | - | |
| 258 | - // callid | |
| 259 | - CallIdHeader callIdHeader = dialog.getCallId(); | |
| 260 | - | |
| 261 | - // Forwards | |
| 262 | - MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); | |
| 263 | - | |
| 264 | - Long cseq = redisCatchStorage.getCSEQ(Request.INVITE); | |
| 265 | - // ceq | |
| 266 | - CSeqHeader cSeqHeader = sipFactory.createHeaderFactory() | |
| 267 | - .createCSeqHeader(cseq, Request.INFO); | |
| 268 | - | |
| 269 | - request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader, | |
| 270 | - fromHeader, toHeader, viaHeaders, maxForwards); | |
| 265 | + // 增加Contact header | |
| 271 | 266 | Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory() |
| 272 | 267 | .createSipURI(sipConfig.getId(), sipConfig.getIp() + ":" + sipConfig.getPort())); |
| 273 | - request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); | |
| 268 | + infoRequest.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); | |
| 269 | + List<String> agentParam = new ArrayList<>(); | |
| 270 | + agentParam.add("wvp-pro"); | |
| 271 | + // TODO 添加版本信息以及日期 | |
| 272 | + UserAgentHeader userAgentHeader = null; | |
| 273 | + try { | |
| 274 | + userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam); | |
| 275 | + } catch (ParseException e) { | |
| 276 | + throw new RuntimeException(e); | |
| 277 | + } | |
| 278 | + infoRequest.addHeader(userAgentHeader); | |
| 274 | 279 | |
| 275 | 280 | ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", |
| 276 | 281 | "MANSRTSP"); |
| 277 | - request.setContent(content, contentTypeHeader); | |
| 278 | - return request; | |
| 282 | + infoRequest.setContent(content, contentTypeHeader); | |
| 283 | + | |
| 284 | + CSeqHeader cSeqHeader = (CSeqHeader)infoRequest.getHeader(CSeqHeader.NAME); | |
| 285 | + cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ()); | |
| 286 | + // ceq | |
| 287 | + infoRequest.addHeader(cSeqHeader); | |
| 288 | + return infoRequest; | |
| 279 | 289 | } |
| 280 | 290 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| ... | ... | @@ -732,8 +732,23 @@ public class SIPCommander implements ISIPCommander { |
| 732 | 732 | SIPRequest request = (SIPRequest)transaction.getRequest(); |
| 733 | 733 | byeURI.setHost(request.getRemoteAddress().getHostAddress()); |
| 734 | 734 | byeURI.setPort(request.getRemotePort()); |
| 735 | + byeURI.setUser(channelId); | |
| 735 | 736 | ViaHeader viaHeader = (ViaHeader) byeRequest.getHeader(ViaHeader.NAME); |
| 736 | 737 | String protocol = viaHeader.getTransport().toUpperCase(); |
| 738 | + viaHeader.setRPort(); | |
| 739 | + // 增加Contact header | |
| 740 | + Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort())); | |
| 741 | + byeRequest.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); | |
| 742 | + List<String> agentParam = new ArrayList<>(); | |
| 743 | + agentParam.add("wvp-pro"); | |
| 744 | + // TODO 添加版本信息以及日期 | |
| 745 | + UserAgentHeader userAgentHeader = null; | |
| 746 | + try { | |
| 747 | + userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam); | |
| 748 | + } catch (ParseException e) { | |
| 749 | + throw new RuntimeException(e); | |
| 750 | + } | |
| 751 | + byeRequest.addHeader(userAgentHeader); | |
| 737 | 752 | ClientTransaction clientTransaction = null; |
| 738 | 753 | if("TCP".equals(protocol)) { |
| 739 | 754 | clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest); |
| ... | ... | @@ -745,11 +760,14 @@ public class SIPCommander implements ISIPCommander { |
| 745 | 760 | if (okEvent != null) { |
| 746 | 761 | sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent); |
| 747 | 762 | } |
| 748 | - | |
| 763 | + CSeqHeader cSeqHeader = (CSeqHeader)byeRequest.getHeader(CSeqHeader.NAME); | |
| 764 | + cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ()); | |
| 749 | 765 | dialog.sendRequest(clientTransaction); |
| 750 | 766 | |
| 751 | 767 | } catch (SipException | ParseException e) { |
| 752 | 768 | e.printStackTrace(); |
| 769 | + } catch (InvalidArgumentException e) { | |
| 770 | + throw new RuntimeException(e); | |
| 753 | 771 | } |
| 754 | 772 | } |
| 755 | 773 | |
| ... | ... | @@ -1483,7 +1501,7 @@ public class SIPCommander implements ISIPCommander { |
| 1483 | 1501 | request.setContent(subscribePostitionXml.toString(), contentTypeHeader); |
| 1484 | 1502 | |
| 1485 | 1503 | CSeqHeader cSeqHeader = (CSeqHeader)request.getHeader(CSeqHeader.NAME); |
| 1486 | - cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ(Request.SUBSCRIBE)); | |
| 1504 | + cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ()); | |
| 1487 | 1505 | request.removeHeader(CSeqHeader.NAME); |
| 1488 | 1506 | request.addHeader(cSeqHeader); |
| 1489 | 1507 | }else { |
| ... | ... | @@ -1587,7 +1605,7 @@ public class SIPCommander implements ISIPCommander { |
| 1587 | 1605 | request.setContent(cmdXml.toString(), contentTypeHeader); |
| 1588 | 1606 | |
| 1589 | 1607 | CSeqHeader cSeqHeader = (CSeqHeader)request.getHeader(CSeqHeader.NAME); |
| 1590 | - cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ(Request.SUBSCRIBE)); | |
| 1608 | + cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ()); | |
| 1591 | 1609 | request.removeHeader(CSeqHeader.NAME); |
| 1592 | 1610 | request.addHeader(cSeqHeader); |
| 1593 | 1611 | |
| ... | ... | @@ -1697,10 +1715,9 @@ public class SIPCommander implements ISIPCommander { |
| 1697 | 1715 | @Override |
| 1698 | 1716 | public void playPauseCmd(Device device, StreamInfo streamInfo) { |
| 1699 | 1717 | try { |
| 1700 | - Long cseq = redisCatchStorage.getCSEQ(Request.INFO); | |
| 1701 | 1718 | StringBuffer content = new StringBuffer(200); |
| 1702 | 1719 | content.append("PAUSE RTSP/1.0\r\n"); |
| 1703 | - content.append("CSeq: " + cseq + "\r\n"); | |
| 1720 | + content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1704 | 1721 | content.append("PauseTime: now\r\n"); |
| 1705 | 1722 | Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString()); |
| 1706 | 1723 | if (request == null) { |
| ... | ... | @@ -1728,10 +1745,9 @@ public class SIPCommander implements ISIPCommander { |
| 1728 | 1745 | @Override |
| 1729 | 1746 | public void playResumeCmd(Device device, StreamInfo streamInfo) { |
| 1730 | 1747 | try { |
| 1731 | - Long cseq = redisCatchStorage.getCSEQ(Request.INFO); | |
| 1732 | 1748 | StringBuffer content = new StringBuffer(200); |
| 1733 | 1749 | content.append("PLAY RTSP/1.0\r\n"); |
| 1734 | - content.append("CSeq: " + cseq + "\r\n"); | |
| 1750 | + content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1735 | 1751 | content.append("Range: npt=now-\r\n"); |
| 1736 | 1752 | Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString()); |
| 1737 | 1753 | if (request == null) { |
| ... | ... | @@ -1758,10 +1774,9 @@ public class SIPCommander implements ISIPCommander { |
| 1758 | 1774 | @Override |
| 1759 | 1775 | public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) { |
| 1760 | 1776 | try { |
| 1761 | - Long cseq = redisCatchStorage.getCSEQ(Request.INFO); | |
| 1762 | 1777 | StringBuffer content = new StringBuffer(200); |
| 1763 | 1778 | content.append("PLAY RTSP/1.0\r\n"); |
| 1764 | - content.append("CSeq: " + cseq + "\r\n"); | |
| 1779 | + content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1765 | 1780 | content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n"); |
| 1766 | 1781 | |
| 1767 | 1782 | Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString()); |
| ... | ... | @@ -1789,11 +1804,11 @@ public class SIPCommander implements ISIPCommander { |
| 1789 | 1804 | @Override |
| 1790 | 1805 | public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) { |
| 1791 | 1806 | try { |
| 1792 | - Long cseq = redisCatchStorage.getCSEQ(Request.INFO); | |
| 1807 | + | |
| 1793 | 1808 | StringBuffer content = new StringBuffer(200); |
| 1794 | 1809 | content.append("PLAY RTSP/1.0\r\n"); |
| 1795 | - content.append("CSeq: " + cseq + "\r\n"); | |
| 1796 | - content.append("Scale: " + String.format("%.1f",speed) + "\r\n"); | |
| 1810 | + content.append("CSeq: " + getInfoCseq() + "\r\n"); | |
| 1811 | + content.append("Scale: " + String.format("%.6f",speed) + "\r\n"); | |
| 1797 | 1812 | Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString()); |
| 1798 | 1813 | if (request == null) { |
| 1799 | 1814 | return; |
| ... | ... | @@ -1812,6 +1827,10 @@ public class SIPCommander implements ISIPCommander { |
| 1812 | 1827 | e.printStackTrace(); |
| 1813 | 1828 | } |
| 1814 | 1829 | } |
| 1830 | + | |
| 1831 | + private int getInfoCseq() { | |
| 1832 | + return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8)); | |
| 1833 | + } | |
| 1815 | 1834 | |
| 1816 | 1835 | @Override |
| 1817 | 1836 | public void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) { |
| ... | ... | @@ -1820,7 +1839,6 @@ public class SIPCommander implements ISIPCommander { |
| 1820 | 1839 | if (request == null) { |
| 1821 | 1840 | return; |
| 1822 | 1841 | } |
| 1823 | - logger.info(request.toString()); | |
| 1824 | 1842 | ClientTransaction clientTransaction = null; |
| 1825 | 1843 | if ("TCP".equals(device.getTransport())) { |
| 1826 | 1844 | clientTransaction = tcpSipProvider.getNewClientTransaction(request); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
| ... | ... | @@ -105,7 +105,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 105 | 105 | } |
| 106 | 106 | |
| 107 | 107 | request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, |
| 108 | - redisCatchStorage.getCSEQ(Request.REGISTER), "FromRegister" + tm, | |
| 108 | + redisCatchStorage.getCSEQ(), "FromRegister" + tm, | |
| 109 | 109 | "z9hG4bK-" + UUID.randomUUID().toString().replace("-", ""), callIdHeader); |
| 110 | 110 | // 将 callid 写入缓存, 等注册成功可以更新状态 |
| 111 | 111 | String callIdFromHeader = callIdHeader.getCallId(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
| ... | ... | @@ -2,24 +2,32 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 4 | 4 | import com.genersoft.iot.vmp.gb28181.SipLayer; |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; | |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| 6 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; |
| 7 | 8 | import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract; |
| 8 | 9 | import gov.nist.javax.sip.ResponseEventExt; |
| 10 | +import gov.nist.javax.sip.message.SIPResponse; | |
| 9 | 11 | import gov.nist.javax.sip.stack.SIPDialog; |
| 10 | 12 | import org.slf4j.Logger; |
| 11 | 13 | import org.slf4j.LoggerFactory; |
| 12 | 14 | import org.springframework.beans.factory.annotation.Autowired; |
| 13 | 15 | import org.springframework.stereotype.Component; |
| 14 | 16 | |
| 15 | -import javax.sip.InvalidArgumentException; | |
| 16 | -import javax.sip.ResponseEvent; | |
| 17 | -import javax.sip.SipException; | |
| 17 | +import javax.sdp.SdpFactory; | |
| 18 | +import javax.sdp.SdpParseException; | |
| 19 | +import javax.sdp.SessionDescription; | |
| 20 | +import javax.sip.*; | |
| 21 | +import javax.sip.address.Address; | |
| 18 | 22 | import javax.sip.address.SipURI; |
| 19 | 23 | import javax.sip.header.CSeqHeader; |
| 24 | +import javax.sip.header.CallIdHeader; | |
| 25 | +import javax.sip.header.UserAgentHeader; | |
| 20 | 26 | import javax.sip.message.Request; |
| 21 | 27 | import javax.sip.message.Response; |
| 22 | 28 | import java.text.ParseException; |
| 29 | +import java.util.ArrayList; | |
| 30 | +import java.util.List; | |
| 23 | 31 | |
| 24 | 32 | |
| 25 | 33 | /** |
| ... | ... | @@ -34,14 +42,16 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { |
| 34 | 42 | private final String method = "INVITE"; |
| 35 | 43 | |
| 36 | 44 | @Autowired |
| 37 | - private SipLayer sipLayer; | |
| 45 | + private VideoStreamSessionManager streamSession; | |
| 38 | 46 | |
| 39 | 47 | @Autowired |
| 40 | - private SipConfig config; | |
| 48 | + private SIPProcessorObserver sipProcessorObserver; | |
| 41 | 49 | |
| 50 | + @Autowired | |
| 51 | + private SipConfig sipConfig; | |
| 42 | 52 | |
| 43 | 53 | @Autowired |
| 44 | - private SIPProcessorObserver sipProcessorObserver; | |
| 54 | + private SipFactory sipFactory; | |
| 45 | 55 | |
| 46 | 56 | @Override |
| 47 | 57 | public void afterPropertiesSet() throws Exception { |
| ... | ... | @@ -49,8 +59,7 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { |
| 49 | 59 | sipProcessorObserver.addResponseProcessor(method, this); |
| 50 | 60 | } |
| 51 | 61 | |
| 52 | - @Autowired | |
| 53 | - private VideoStreamSessionManager streamSession; | |
| 62 | + | |
| 54 | 63 | |
| 55 | 64 | /** |
| 56 | 65 | * 处理invite响应 |
| ... | ... | @@ -74,6 +83,19 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { |
| 74 | 83 | CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME); |
| 75 | 84 | Request reqAck = dialog.createAck(cseq.getSeqNumber()); |
| 76 | 85 | SipURI requestURI = (SipURI) reqAck.getRequestURI(); |
| 86 | + String contentString = new String(response.getRawContent()); | |
| 87 | + // jainSip不支持y=字段, 移除以解析。 | |
| 88 | + int ssrcIndex = contentString.indexOf("y="); | |
| 89 | + // 检查是否有y字段 | |
| 90 | + SessionDescription sdp; | |
| 91 | + if (ssrcIndex >= 0) { | |
| 92 | + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 | |
| 93 | + String substring = contentString.substring(0, contentString.indexOf("y=")); | |
| 94 | + sdp = SdpFactory.getInstance().createSessionDescription(substring); | |
| 95 | + } else { | |
| 96 | + sdp = SdpFactory.getInstance().createSessionDescription(contentString); | |
| 97 | + } | |
| 98 | + requestURI.setUser(sdp.getOrigin().getUsername()); | |
| 77 | 99 | try { |
| 78 | 100 | requestURI.setHost(event.getRemoteIpAddress()); |
| 79 | 101 | } catch (ParseException e) { |
| ... | ... | @@ -81,6 +103,18 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { |
| 81 | 103 | } |
| 82 | 104 | requestURI.setPort(event.getRemotePort()); |
| 83 | 105 | reqAck.setRequestURI(requestURI); |
| 106 | + List<String> agentParam = new ArrayList<>(); | |
| 107 | + agentParam.add("wvp-pro"); | |
| 108 | + // TODO 添加版本信息以及日期 | |
| 109 | + UserAgentHeader userAgentHeader = null; | |
| 110 | + try { | |
| 111 | + userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam); | |
| 112 | + } catch (ParseException e) { | |
| 113 | + throw new RuntimeException(e); | |
| 114 | + } | |
| 115 | + reqAck.addHeader(userAgentHeader); | |
| 116 | + Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort())); | |
| 117 | + reqAck.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); | |
| 84 | 118 | logger.info("[回复ack] {}-> {}:{} ",requestURI, event.getRemoteIpAddress(), event.getRemotePort()); |
| 85 | 119 | |
| 86 | 120 | dialog.sendAck(reqAck); |
| ... | ... | @@ -88,6 +122,10 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { |
| 88 | 122 | } |
| 89 | 123 | } catch (InvalidArgumentException | SipException e) { |
| 90 | 124 | e.printStackTrace(); |
| 125 | + } catch (ParseException e) { | |
| 126 | + throw new RuntimeException(e); | |
| 127 | + } catch (SdpParseException e) { | |
| 128 | + throw new RuntimeException(e); | |
| 91 | 129 | } |
| 92 | 130 | } |
| 93 | 131 | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| ... | ... | @@ -98,9 +98,7 @@ public class ZLMHttpHookListener { |
| 98 | 98 | @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8") |
| 99 | 99 | public ResponseEntity<String> onServerKeepalive(@RequestBody JSONObject json){ |
| 100 | 100 | |
| 101 | - if (logger.isDebugEnabled()) { | |
| 102 | - logger.debug("[ ZLM HOOK ] on_server_keepalive API调用,参数:" + json.toString()); | |
| 103 | - } | |
| 101 | + logger.info("[ ZLM HOOK ] on_server_keepalive API调用,参数:" + json.toString()); | |
| 104 | 102 | String mediaServerId = json.getString("mediaServerId"); |
| 105 | 103 | List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive); |
| 106 | 104 | if (subscribes != null && subscribes.size() > 0) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
| ... | ... | @@ -277,13 +277,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 277 | 277 | return null; |
| 278 | 278 | } |
| 279 | 279 | String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerId; |
| 280 | - MediaServerItem serverItem=(MediaServerItem)redisUtil.get(key); | |
| 281 | - if(null==serverItem){ | |
| 282 | - //zlm服务不在线,启动重连 | |
| 283 | - reloadZlm(); | |
| 284 | - serverItem=(MediaServerItem)redisUtil.get(key); | |
| 285 | - } | |
| 286 | - return serverItem; | |
| 280 | + return (MediaServerItem)redisUtil.get(key); | |
| 287 | 281 | } |
| 288 | 282 | |
| 289 | 283 | @Override |
| ... | ... | @@ -412,7 +406,6 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 412 | 406 | } |
| 413 | 407 | redisUtil.set(key, serverItem); |
| 414 | 408 | resetOnlineServerItem(serverItem); |
| 415 | - updateMediaServerKeepalive(serverItem.getId(), null); | |
| 416 | 409 | if (serverItem.isAutoConfig()) { |
| 417 | 410 | setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable())); |
| 418 | 411 | } |
| ... | ... | @@ -476,9 +469,6 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 476 | 469 | String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId(); |
| 477 | 470 | |
| 478 | 471 | if (redisUtil.zSize(key) == null || redisUtil.zSize(key) == 0) { |
| 479 | - logger.info("获取负载最低的节点时无在线节点,启动重连机制"); | |
| 480 | - //启动重连 | |
| 481 | - reloadZlm(); | |
| 482 | 472 | if (redisUtil.zSize(key) == null || redisUtil.zSize(key) == 0) { |
| 483 | 473 | logger.info("获取负载最低的节点时无在线节点"); |
| 484 | 474 | return null; |
| ... | ... | @@ -643,6 +633,11 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 643 | 633 | public void updateMediaServerKeepalive(String mediaServerId, JSONObject data) { |
| 644 | 634 | MediaServerItem mediaServerItem = getOne(mediaServerId); |
| 645 | 635 | if (mediaServerItem == null) { |
| 636 | + // 缓存不存在,从数据库查询,如果数据库不存在则是错误的 | |
| 637 | + MediaServerItem mediaServerItemFromDatabase = getOneFromDatabase(mediaServerId); | |
| 638 | + if (mediaServerItemFromDatabase == null) { | |
| 639 | + return; | |
| 640 | + } | |
| 646 | 641 | // zlm连接重试 |
| 647 | 642 | logger.warn("[更新ZLM 保活信息]失败,未找到流媒体信息,尝试重连zlm"); |
| 648 | 643 | reloadZlm(); |
| ... | ... | @@ -658,6 +653,10 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 658 | 653 | redisUtil.set(key, data, hookAliveInterval); |
| 659 | 654 | } |
| 660 | 655 | |
| 656 | + private MediaServerItem getOneFromDatabase(String mediaServerId) { | |
| 657 | + return mediaServerMapper.queryOne(mediaServerId); | |
| 658 | + } | |
| 659 | + | |
| 661 | 660 | @Override |
| 662 | 661 | public void syncCatchFromDatabase() { |
| 663 | 662 | List<MediaServerItem> allInCatch = getAll(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
| ... | ... | @@ -42,8 +42,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 42 | 42 | private UserSetting userSetting; |
| 43 | 43 | |
| 44 | 44 | @Override |
| 45 | - public Long getCSEQ(String method) { | |
| 46 | - String key = VideoManagerConstants.SIP_CSEQ_PREFIX + userSetting.getServerId() + "_" + method; | |
| 45 | + public Long getCSEQ() { | |
| 46 | + String key = VideoManagerConstants.SIP_CSEQ_PREFIX + userSetting.getServerId(); | |
| 47 | 47 | |
| 48 | 48 | long result = redis.incr(key, 1L); |
| 49 | 49 | if (result > Integer.MAX_VALUE) { | ... | ... |