Commit 92cbbefcf4773ba136f15afa1ca89e9c050b1aba
Committed by
GitHub
Merge pull request #10 from lawrencehj/master
修正Invite后无法发送ack、bye无法找到对话对方IP地址的问题等
Showing
7 changed files
with
97 additions
and
43 deletions
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181; |
| 2 | 2 | |
| 3 | +import java.text.ParseException; | |
| 3 | 4 | import java.util.Properties; |
| 4 | 5 | |
| 5 | 6 | import javax.annotation.PostConstruct; |
| ... | ... | @@ -128,11 +129,18 @@ public class SipLayer implements SipListener, Runnable { |
| 128 | 129 | int status = response.getStatusCode(); |
| 129 | 130 | if ((status >= 200) && (status < 300)) { // Success! |
| 130 | 131 | ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt); |
| 131 | - processor.process(evt, this, sipConfig); | |
| 132 | - } else if (status == Response.TRYING) { | |
| 132 | + try { | |
| 133 | + processor.process(evt, this, sipConfig); | |
| 134 | + } catch (ParseException e) { | |
| 135 | + // TODO Auto-generated catch block | |
| 136 | + e.printStackTrace(); | |
| 137 | + } | |
| 138 | + // } else if (status == Response.TRYING) { | |
| 133 | 139 | // trying不会回复 |
| 140 | + } else if ((status >= 100) && (status < 200)) { | |
| 141 | + // 增加其它无需回复的响应,如101、180等 | |
| 134 | 142 | } else { |
| 135 | - logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getContent().toString()); | |
| 143 | + logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/); | |
| 136 | 144 | } |
| 137 | 145 | // trying不会回复 |
| 138 | 146 | // if (status == Response.TRYING) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
| ... | ... | @@ -79,7 +79,8 @@ public class SIPRequestHeaderProvider { |
| 79 | 79 | SipURI requestLine = layer.getAddressFactory().createSipURI(channelId, host.getAddress()); |
| 80 | 80 | //via |
| 81 | 81 | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
| 82 | - ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag); | |
| 82 | + // ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag); | |
| 83 | + ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(device.getHost().getIp(), device.getHost().getPort(), device.getTransport(), viaTag); | |
| 83 | 84 | viaHeader.setRPort(); |
| 84 | 85 | viaHeaders.add(viaHeader); |
| 85 | 86 | //from |
| ... | ... | @@ -108,6 +109,7 @@ public class SIPRequestHeaderProvider { |
| 108 | 109 | request = layer.getMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); |
| 109 | 110 | |
| 110 | 111 | Address concatAddress = layer.getAddressFactory().createAddress(layer.getAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); |
| 112 | + // Address concatAddress = layer.getAddressFactory().createAddress(layer.getAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort())); | |
| 111 | 113 | request.addHeader(layer.getHeaderFactory().createContactHeader(concatAddress)); |
| 112 | 114 | |
| 113 | 115 | ContentTypeHeader contentTypeHeader = layer.getHeaderFactory().createContentTypeHeader("Application", "SDP"); |
| ... | ... | @@ -122,7 +124,8 @@ public class SIPRequestHeaderProvider { |
| 122 | 124 | SipURI requestLine = layer.getAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); |
| 123 | 125 | //via |
| 124 | 126 | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
| 125 | - ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag); | |
| 127 | + // ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag); | |
| 128 | + ViaHeader viaHeader = layer.getHeaderFactory().createViaHeader(device.getHost().getIp(), device.getHost().getPort(), device.getTransport(), viaTag); | |
| 126 | 129 | viaHeader.setRPort(); |
| 127 | 130 | viaHeaders.add(viaHeader); |
| 128 | 131 | //from |
| ... | ... | @@ -151,6 +154,7 @@ public class SIPRequestHeaderProvider { |
| 151 | 154 | request = layer.getMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); |
| 152 | 155 | |
| 153 | 156 | Address concatAddress = layer.getAddressFactory().createAddress(layer.getAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort())); |
| 157 | + // Address concatAddress = layer.getAddressFactory().createAddress(layer.getAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort())); | |
| 154 | 158 | request.addHeader(layer.getHeaderFactory().createContactHeader(concatAddress)); |
| 155 | 159 | |
| 156 | 160 | ContentTypeHeader contentTypeHeader = layer.getHeaderFactory().createContentTypeHeader("Application", "SDP"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| ... | ... | @@ -7,10 +7,13 @@ import javax.sip.Dialog; |
| 7 | 7 | import javax.sip.InvalidArgumentException; |
| 8 | 8 | import javax.sip.SipException; |
| 9 | 9 | import javax.sip.TransactionDoesNotExistException; |
| 10 | +import javax.sip.address.Address; | |
| 11 | +import javax.sip.address.SipURI; | |
| 10 | 12 | import javax.sip.header.ViaHeader; |
| 11 | 13 | import javax.sip.message.Request; |
| 12 | 14 | |
| 13 | 15 | import org.springframework.beans.factory.annotation.Autowired; |
| 16 | +import org.springframework.boot.autoconfigure.security.SecurityProperties.Headers; | |
| 14 | 17 | import org.springframework.stereotype.Component; |
| 15 | 18 | |
| 16 | 19 | import com.genersoft.iot.vmp.conf.SipConfig; |
| ... | ... | @@ -21,6 +24,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 21 | 24 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; |
| 22 | 25 | import com.genersoft.iot.vmp.gb28181.utils.DateUtil; |
| 23 | 26 | |
| 27 | +import java.util.regex.Pattern; | |
| 28 | +import java.util.regex.Matcher; | |
| 29 | + | |
| 24 | 30 | /** |
| 25 | 31 | * @Description:设备能力接口,用于定义设备的控制、查询能力 |
| 26 | 32 | * @author: songww |
| ... | ... | @@ -288,6 +294,13 @@ public class SIPCommander implements ISIPCommander { |
| 288 | 294 | return; |
| 289 | 295 | } |
| 290 | 296 | Request byeRequest = dialog.createRequest(Request.BYE); |
| 297 | + SipURI byeURI = (SipURI) byeRequest.getRequestURI(); | |
| 298 | + String vh = transaction.getRequest().getHeader(ViaHeader.NAME).toString(); | |
| 299 | + Pattern p = Pattern.compile("(\\d+\\.\\d+\\.\\d+\\.\\d+)\\:(\\d+)"); | |
| 300 | + Matcher matcher = p.matcher(vh); | |
| 301 | + if (matcher.find()) { | |
| 302 | + byeURI.setHost(matcher.group(1)); | |
| 303 | + } | |
| 291 | 304 | ViaHeader viaHeader = (ViaHeader) byeRequest.getHeader(ViaHeader.NAME); |
| 292 | 305 | String protocol = viaHeader.getTransport().toUpperCase(); |
| 293 | 306 | ClientTransaction clientTransaction = null; |
| ... | ... | @@ -301,6 +314,8 @@ public class SIPCommander implements ISIPCommander { |
| 301 | 314 | e.printStackTrace(); |
| 302 | 315 | } catch (SipException e) { |
| 303 | 316 | e.printStackTrace(); |
| 317 | + } catch (ParseException e) { | |
| 318 | + e.printStackTrace(); | |
| 304 | 319 | } |
| 305 | 320 | } |
| 306 | 321 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
| ... | ... | @@ -100,6 +100,7 @@ public class MessageRequestProcessor implements ISIPRequestProcessor { |
| 100 | 100 | |
| 101 | 101 | Request request = evt.getRequest(); |
| 102 | 102 | SAXReader reader = new SAXReader(); |
| 103 | + reader.setEncoding("gbk"); | |
| 103 | 104 | Document xml; |
| 104 | 105 | try { |
| 105 | 106 | xml = reader.read(new ByteArrayInputStream(request.getRawContent())); |
| ... | ... | @@ -375,7 +376,7 @@ public class MessageRequestProcessor implements ISIPRequestProcessor { |
| 375 | 376 | private Element getRootElement(RequestEvent evt) throws DocumentException { |
| 376 | 377 | Request request = evt.getRequest(); |
| 377 | 378 | SAXReader reader = new SAXReader(); |
| 378 | - reader.setEncoding("GB2312"); | |
| 379 | + reader.setEncoding("gbk"); | |
| 379 | 380 | Document xml = reader.read(new ByteArrayInputStream(request.getRawContent())); |
| 380 | 381 | return xml.getRootElement(); |
| 381 | 382 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/ISIPResponseProcessor.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.transmit.response; |
| 2 | 2 | |
| 3 | +import java.text.ParseException; | |
| 4 | + | |
| 3 | 5 | import javax.sip.ResponseEvent; |
| 4 | 6 | |
| 5 | 7 | import com.genersoft.iot.vmp.conf.SipConfig; |
| ... | ... | @@ -12,6 +14,6 @@ import com.genersoft.iot.vmp.gb28181.SipLayer; |
| 12 | 14 | */ |
| 13 | 15 | public interface ISIPResponseProcessor { |
| 14 | 16 | |
| 15 | - public void process(ResponseEvent evt, SipLayer layer, SipConfig config); | |
| 17 | + public void process(ResponseEvent evt, SipLayer layer, SipConfig config) throws ParseException; | |
| 16 | 18 | |
| 17 | 19 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java
| ... | ... | @@ -7,8 +7,11 @@ import javax.sip.Dialog; |
| 7 | 7 | import javax.sip.InvalidArgumentException; |
| 8 | 8 | import javax.sip.ResponseEvent; |
| 9 | 9 | import javax.sip.SipException; |
| 10 | +import javax.sip.address.Address; | |
| 10 | 11 | import javax.sip.address.SipURI; |
| 11 | 12 | import javax.sip.header.CSeqHeader; |
| 13 | +import javax.sip.header.ContactHeader; | |
| 14 | +import javax.sip.header.FromHeader; | |
| 12 | 15 | import javax.sip.header.ViaHeader; |
| 13 | 16 | import javax.sip.message.Request; |
| 14 | 17 | import javax.sip.message.Response; |
| ... | ... | @@ -22,57 +25,78 @@ import com.genersoft.iot.vmp.gb28181.SipLayer; |
| 22 | 25 | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorFactory; |
| 23 | 26 | import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; |
| 24 | 27 | |
| 25 | -/** | |
| 28 | +// import java.util.regex.Pattern; | |
| 29 | +// import java.util.regex.Matcher; | |
| 30 | + | |
| 31 | +/** | |
| 26 | 32 | * @Description:处理INVITE响应 |
| 27 | 33 | * @author: songww |
| 28 | - * @date: 2020年5月3日 下午4:43:52 | |
| 34 | + * @date: 2020年5月3日 下午4:43:52 | |
| 29 | 35 | */ |
| 30 | 36 | @Component |
| 31 | 37 | public class InviteResponseProcessor implements ISIPResponseProcessor { |
| 32 | 38 | |
| 33 | 39 | private final static Logger logger = LoggerFactory.getLogger(SIPProcessorFactory.class); |
| 34 | - | |
| 40 | + | |
| 35 | 41 | /** |
| 36 | 42 | * 处理invite响应 |
| 37 | 43 | * |
| 38 | - * @param evt | |
| 39 | - * 响应消息 | |
| 40 | - */ | |
| 44 | + * @param evt 响应消息 | |
| 45 | + * @throws ParseException | |
| 46 | + */ | |
| 41 | 47 | @Override |
| 42 | - public void process(ResponseEvent evt, SipLayer layer, SipConfig config) { | |
| 48 | + public void process(ResponseEvent evt, SipLayer layer, SipConfig config) throws ParseException { | |
| 43 | 49 | try { |
| 44 | 50 | Response response = evt.getResponse(); |
| 45 | 51 | int statusCode = response.getStatusCode(); |
| 46 | - //trying不会回复 | |
| 47 | - if(statusCode == Response.TRYING){ | |
| 48 | - | |
| 52 | + // trying不会回复 | |
| 53 | + if (statusCode == Response.TRYING) { | |
| 49 | 54 | } |
| 50 | - //成功响应 | |
| 51 | - //下发ack | |
| 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); | |
| 73 | - | |
| 55 | + // 成功响应 | |
| 56 | + // 下发ack | |
| 57 | + if (statusCode == Response.OK) { | |
| 58 | + // ClientTransaction clientTransaction = evt.getClientTransaction(); | |
| 59 | + // if(clientTransaction == null){ | |
| 60 | + // logger.error("回复ACK时,clientTransaction为null >>> {}",response); | |
| 61 | + // return; | |
| 62 | + // } | |
| 63 | + // Dialog clientDialog = clientTransaction.getDialog(); | |
| 64 | + | |
| 65 | + // CSeqHeader clientCSeqHeader = (CSeqHeader) | |
| 66 | + // response.getHeader(CSeqHeader.NAME); | |
| 67 | + // long cseqId = clientCSeqHeader.getSeqNumber(); | |
| 68 | + // /* | |
| 69 | + // createAck函数,创建的ackRequest,会采用Invite响应的200OK,中的contact字段中的地址,作为目标地址。 | |
| 70 | + // 有的终端传上来的可能还是内网地址,会造成ack发送不出去。接受不到音视频流 | |
| 71 | + // 所以在此处统一替换地址。和响应消息的Via头中的地址保持一致。 | |
| 72 | + // */ | |
| 73 | + // Request ackRequest = clientDialog.createAck(cseqId); | |
| 74 | + // SipURI requestURI = (SipURI) ackRequest.getRequestURI(); | |
| 75 | + // ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME); | |
| 76 | + // try { | |
| 77 | + // requestURI.setHost(viaHeader.getHost()); | |
| 78 | + // } catch (Exception e) { | |
| 79 | + // e.printStackTrace(); | |
| 80 | + // } | |
| 81 | + // requestURI.setPort(viaHeader.getPort()); | |
| 82 | + // clientDialog.sendAck(ackRequest); | |
| 83 | + | |
| 74 | 84 | Dialog dialog = evt.getDialog(); |
| 75 | - Request reqAck =dialog.createAck(1L); | |
| 85 | + CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME); | |
| 86 | + Request reqAck = dialog.createAck(cseq.getSeqNumber()); | |
| 87 | + | |
| 88 | + SipURI requestURI = (SipURI) reqAck.getRequestURI(); | |
| 89 | + ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME); | |
| 90 | + // String viaHost =viaHeader.getHost(); | |
| 91 | + //getHost()函数取回的IP地址是“[xxx.xxx.xxx.xxx:yyyy]”的格式,需用正则表达式截取为“xxx.xxx.xxx.xxx"格式 | |
| 92 | + // Pattern p = Pattern.compile("(?<=//|)((\\w)+\\.)+\\w+"); | |
| 93 | + // Matcher matcher = p.matcher(viaHeader.getHost()); | |
| 94 | + // if (matcher.find()) { | |
| 95 | + // requestURI.setHost(matcher.group()); | |
| 96 | + // } | |
| 97 | + requestURI.setHost(viaHeader.getHost()); | |
| 98 | + requestURI.setPort(viaHeader.getPort()); | |
| 99 | + reqAck.setRequestURI(requestURI); | |
| 76 | 100 | dialog.sendAck(reqAck); |
| 77 | 101 | } |
| 78 | 102 | } catch (InvalidArgumentException | SipException e) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| ... | ... | @@ -22,7 +22,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 22 | 22 | * @date: 2020年5月8日 上午10:46:48 |
| 23 | 23 | */ |
| 24 | 24 | @RestController |
| 25 | -@RequestMapping("/hook/zlm") | |
| 25 | +@RequestMapping("/index/hook") | |
| 26 | 26 | public class ZLMHttpHookListener { |
| 27 | 27 | |
| 28 | 28 | private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class); | ... | ... |