Commit ef742e715b8c0a983d661aa5b5f8980dade8c790

Authored by panlinlin
1 parent 118e4288

优化宕机后点播中设备发送bye

src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
... ... @@ -21,6 +21,15 @@ public class StreamInfo {
21 21 private String rtc;
22 22 private JSONArray tracks;
23 23  
  24 + public static class TransactionInfo{
  25 + public String callId;
  26 + public String localTag;
  27 + public String remoteTag;
  28 + public String branch;
  29 + }
  30 +
  31 + private TransactionInfo transactionInfo;
  32 +
24 33 public String getApp() {
25 34 return app;
26 35 }
... ... @@ -148,4 +157,12 @@ public class StreamInfo {
148 157 public void setRtc(String rtc) {
149 158 this.rtc = rtc;
150 159 }
  160 +
  161 + public TransactionInfo getTransactionInfo() {
  162 + return transactionInfo;
  163 + }
  164 +
  165 + public void setTransactionInfo(TransactionInfo transactionInfo) {
  166 + this.transactionInfo = transactionInfo;
  167 + }
151 168 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
... ... @@ -135,6 +135,36 @@ public class SIPRequestHeaderProvider {
135 135 return request;
136 136 }
137 137  
  138 + public Request createByteRequest(Device device, String channelId, String viaTag, String fromTag, String toTag, String callId) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  139 + Request request = null;
  140 + //请求行
  141 + SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
  142 + // via
  143 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  144 + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag);
  145 + viaHeaders.add(viaHeader);
  146 + //from
  147 + SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain());
  148 + Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
  149 + FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
  150 + //to
  151 + SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,sipConfig.getSipDomain());
  152 + Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
  153 + ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress,toTag);
  154 +
  155 + //Forwards
  156 + MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
  157 +
  158 + //ceq
  159 + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.BYE);
  160 + CallIdHeader callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(callId);
  161 + request = sipFactory.createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  162 +
  163 + Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort()));
  164 +
  165 + return request;
  166 + }
  167 +
138 168 public Request createSubscribeRequest(Device device, String content, String viaTag, String fromTag, String toTag, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
139 169 Request request = null;
140 170 // sipuri
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
... ... @@ -10,11 +10,14 @@ import javax.sip.header.CallIdHeader;
10 10 import javax.sip.header.ViaHeader;
11 11 import javax.sip.message.Request;
12 12  
  13 +import com.alibaba.fastjson.JSON;
  14 +import com.alibaba.fastjson.JSONArray;
13 15 import com.alibaba.fastjson.JSONObject;
14 16 import com.genersoft.iot.vmp.common.StreamInfo;
15 17 import com.genersoft.iot.vmp.conf.MediaServerConfig;
16 18 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
17 19 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
  20 +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
18 21 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
19 22 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
20 23 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
... ... @@ -75,6 +78,9 @@ public class SIPCommander implements ISIPCommander {
75 78 @Autowired
76 79 private ZLMRTPServerFactory zlmrtpServerFactory;
77 80  
  81 + @Autowired
  82 + private ZLMRESTfulUtils zlmresTfulUtils;
  83 +
78 84 @Value("${media.rtp.enable}")
79 85 private boolean rtpEnable;
80 86  
... ... @@ -577,13 +583,39 @@ public class SIPCommander implements ISIPCommander {
577 583  
578 584 try {
579 585 ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId);
580   - // 服务重启后
  586 + // 服务重启后, 无法直接发送bye, 通过手动构建发送
581 587 if (transaction == null) {
  588 +
582 589 StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
583 590 if (streamInfo != null) {
  591 + JSONObject mediaList = zlmresTfulUtils.getMediaList(streamInfo.getApp(), streamInfo.getStreamId());
  592 + if (mediaList != null) { // 仍在推流才发送
  593 + if (mediaList.getInteger("code") == 0) {
  594 + JSONArray data = mediaList.getJSONArray("data");
  595 + if (data != null && data.size() > 0) {
  596 + Device device = storager.queryVideoDevice(deviceId);
  597 + if (device != null) {
  598 + StreamInfo.TransactionInfo transactionInfo = streamInfo.getTransactionInfo();
  599 + try {
  600 + Request byteRequest = headerProvider.createByteRequest(device, channelId,
  601 + transactionInfo.branch,
  602 + transactionInfo.localTag,
  603 + transactionInfo.remoteTag,
  604 + transactionInfo.callId);
  605 + transmitRequest(device, byteRequest);
  606 + } catch (InvalidArgumentException e) {
  607 + e.printStackTrace();
  608 + }
  609 + }
  610 + }
  611 + }
  612 + }
584 613 redisCatchStorage.stopPlay(streamInfo);
585 614 }
586   - okEvent.response(null);
  615 +
  616 + if (okEvent != null) {
  617 + okEvent.response(null);
  618 + }
587 619 return;
588 620 }
589 621  
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
... ... @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.common.StreamInfo;
7 7 import com.genersoft.iot.vmp.gb28181.bean.Device;
8 8 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
9 9 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  10 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
10 11 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
11 12 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
12 13 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
... ... @@ -17,6 +18,7 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
17 18 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
18 19 import com.genersoft.iot.vmp.service.IMediaService;
19 20 import com.genersoft.iot.vmp.service.IPlayService;
  21 +import gov.nist.javax.sip.stack.SIPDialog;
20 22 import org.slf4j.Logger;
21 23 import org.slf4j.LoggerFactory;
22 24 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -24,6 +26,9 @@ import org.springframework.http.ResponseEntity;
24 26 import org.springframework.stereotype.Service;
25 27 import org.springframework.web.context.request.async.DeferredResult;
26 28  
  29 +import javax.sip.ClientTransaction;
  30 +import javax.sip.Dialog;
  31 +import javax.sip.header.CallIdHeader;
27 32 import javax.sip.message.Response;
28 33 import java.util.UUID;
29 34  
... ... @@ -50,6 +55,9 @@ public class PlayServiceImpl implements IPlayService {
50 55 @Autowired
51 56 private IMediaService mediaService;
52 57  
  58 + @Autowired
  59 + private VideoStreamSessionManager streamSession;
  60 +
53 61  
54 62 @Override
55 63 public PlayResult play(String deviceId, String channelId, ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent) {
... ... @@ -141,7 +149,14 @@ public class PlayServiceImpl implements IPlayService {
141 149 deviceChannel.setStreamId(streamInfo.getStreamId());
142 150 storager.startPlay(deviceId, channelId, streamInfo.getStreamId());
143 151 }
144   -
  152 + ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId);
  153 + SIPDialog dialog = (SIPDialog)transaction.getDialog();
  154 + StreamInfo.TransactionInfo transactionInfo = new StreamInfo.TransactionInfo();
  155 + transactionInfo.callId = dialog.getCallId().getCallId();
  156 + transactionInfo.localTag = dialog.getLocalTag();
  157 + transactionInfo.remoteTag = dialog.getRemoteTag();
  158 + transactionInfo.branch = dialog.getFirstTransactionInt().getBranchId();
  159 + streamInfo.setTransactionInfo(transactionInfo);
145 160 redisCatchStorage.startPlay(streamInfo);
146 161 msg.setData(JSON.toJSONString(streamInfo));
147 162 resultHolder.invokeResult(msg);
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
... ... @@ -102,6 +102,7 @@ public class PlayController {
102 102 msg.setId(DeferredResultHolder.CALLBACK_CMD_STOP + uuid);
103 103 msg.setData("点播未找到");
104 104 resultHolder.invokeResult(msg);
  105 + storager.stopPlay(deviceId, channelId);
105 106 }else {
106 107 redisCatchStorage.stopPlay(streamInfo);
107 108 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
... ...