朱俊杰
2022-03-16 ba3c38d7d352800ccda6c68bb015b071d0794b42
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -2,9 +2,12 @@
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
@@ -84,6 +87,9 @@
   @Autowired
   private IMediaServerService mediaServerService;
   @Autowired
   private DynamicTask dynamicTask;
   /**
@@ -330,7 +336,8 @@
     * @param errorEvent sip错误订阅
     */
   @Override
   public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
   public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
                       ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
      String streamId = ssrcInfo.getStream();
      try {
         if (device == null) return;
@@ -342,12 +349,13 @@
         subscribeKey.put("app", "rtp");
         subscribeKey.put("stream", streamId);
         subscribeKey.put("regist", true);
         subscribeKey.put("schema", "rtmp");
         subscribeKey.put("mediaServerId", mediaServerItem.getId());
         subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
               (MediaServerItem mediaServerItemInUse, JSONObject json)->{
            if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
            event.response(mediaServerItemInUse, json);
            subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
            if (event != null) {
               event.response(mediaServerItemInUse, json);
            }
         });
         //
         StringBuffer content = new StringBuffer(200);
@@ -416,7 +424,7 @@
         transmitRequest(device, request, (e -> {
            streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
            mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc());
            mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
            errorEvent.response(e);
         }), e ->{
            // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
@@ -439,25 +447,12 @@
    * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
    */ 
   @Override
   public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
         , SipSubscribe.Event errorEvent) {
   public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
                          String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
                          SipSubscribe.Event errorEvent) {
      try {
         logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
         // 添加订阅
         JSONObject subscribeKey = new JSONObject();
         subscribeKey.put("app", "rtp");
         subscribeKey.put("stream", ssrcInfo.getStream());
         subscribeKey.put("regist", true);
         subscribeKey.put("mediaServerId", mediaServerItem.getId());
         logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
         subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
               (MediaServerItem mediaServerItemInUse, JSONObject json)->{
            if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
            event.response(mediaServerItemInUse, json);
            subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
         });
         StringBuffer content = new StringBuffer(200);
           content.append("v=0\r\n");
@@ -523,6 +518,21 @@
         CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
               : udpSipProvider.getNewCallId();
         // 添加订阅
         JSONObject subscribeKey = new JSONObject();
         subscribeKey.put("app", "rtp");
         subscribeKey.put("stream", ssrcInfo.getStream());
         subscribeKey.put("regist", true);
         subscribeKey.put("schema", "rtmp");
         subscribeKey.put("mediaServerId", mediaServerItem.getId());
         logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey);
         subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
               (MediaServerItem mediaServerItemInUse, JSONObject json)->{
                  if (hookEvent != null) {
                     InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream());
                     hookEvent.call(inviteStreamInfo);
                  }
               });
           Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
           transmitRequest(device, request, errorEvent, okEvent -> {
@@ -530,6 +540,9 @@
              streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction());
            streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
         });
         if (inviteStreamCallback != null) {
            inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
         }
      } catch ( SipException | ParseException | InvalidArgumentException e) {
         e.printStackTrace();
      }
@@ -545,24 +558,10 @@
    * @param downloadSpeed 下载倍速参数
    */ 
   @Override
   public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event
   public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, InviteStreamCallback event
         , SipSubscribe.Event errorEvent) {
      try {
         logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
         // 添加订阅
         JSONObject subscribeKey = new JSONObject();
         subscribeKey.put("app", "rtp");
         subscribeKey.put("stream", ssrcInfo.getStream());
         subscribeKey.put("regist", true);
         subscribeKey.put("mediaServerId", mediaServerItem.getId());
         logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
         subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
               (MediaServerItem mediaServerItemInUse, JSONObject json)->{
            if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
            event.response(mediaServerItemInUse, json);
            subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
         });
         StringBuffer content = new StringBuffer(200);
           content.append("v=0\r\n");
@@ -631,6 +630,19 @@
         CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
               : udpSipProvider.getNewCallId();
         // 添加订阅
         JSONObject subscribeKey = new JSONObject();
         subscribeKey.put("app", "rtp");
         subscribeKey.put("stream", ssrcInfo.getStream());
         subscribeKey.put("regist", true);
         subscribeKey.put("mediaServerId", mediaServerItem.getId());
         logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
         subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
               (MediaServerItem mediaServerItemInUse, JSONObject json)->{
                  event.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
                  subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
               });
           Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
           ClientTransaction transaction = transmitRequest(device, request, errorEvent);
@@ -646,16 +658,17 @@
    * 视频流停止, 不使用回调
    */
   @Override
   public void streamByeCmd(String deviceId, String channelId, String stream) {
      streamByeCmd(deviceId, channelId, stream, null);
   public void streamByeCmd(String deviceId, String channelId, String stream, String callId) {
      streamByeCmd(deviceId, channelId, stream, callId, null);
   }
   /**
    * 视频流停止
    */
   @Override
   public void streamByeCmd(String deviceId, String channelId, String stream, SipSubscribe.Event okEvent) {
   public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) {
      try {
         SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, null, stream);
         ClientTransaction transaction = streamSession.getTransactionByStream(deviceId, channelId, stream);
         if (transaction == null) {
            logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
@@ -665,7 +678,15 @@
            }
            return;
         }
         SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, stream);
         SIPDialog dialog;
         if (callId != null) {
            dialog = streamSession.getDialogByCallId(deviceId, channelId, callId);
         }else {
            if (stream == null) return;
            dialog = streamSession.getDialogByStream(deviceId, channelId, stream);
         }
         if (dialog == null) {
            logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId);
            return;
@@ -709,10 +730,10 @@
         dialog.sendRequest(clientTransaction);
         SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, callIdHeader.getCallId(), null);
         if (ssrcTransaction != null) {
            MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
            mediaServerService.releaseSsrc(mediaServerItem, ssrcTransaction.getSsrc());
            mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc());
            mediaServerService.closeRTPServer(deviceId, channelId, ssrcTransaction.getStream());
            streamSession.remove(deviceId, channelId, ssrcTransaction.getStream());
         }
      } catch (SipException | ParseException e) {
@@ -1162,8 +1183,6 @@
    */ 
   @Override
   public boolean catalogQuery(Device device, SipSubscribe.Event errorEvent) {
      // 清空通道
//      storager.cleanChannelsForDevice(device.getDeviceId());
      try {
         StringBuffer catalogXml = new StringBuffer(200);
         catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
@@ -1196,9 +1215,13 @@
    * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
    */  
   @Override
   public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, SipSubscribe.Event errorEvent) {
   public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
      if (secrecy == null) {
         secrecy = 0;
      }
      if (type == null) {
         type = "all";
      }
      try {
         StringBuffer recordInfoXml = new StringBuffer(200);
         recordInfoXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
@@ -1206,11 +1229,19 @@
         recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");
         recordInfoXml.append("<SN>" + sn + "</SN>\r\n");
         recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
         recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
         recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
         recordInfoXml.append("<Secrecy>0</Secrecy>\r\n");
         // 大华NVR要求必须增加一个值为all的文本元素节点Type
         recordInfoXml.append("<Type>all</Type>\r\n");
         if (startTime != null) {
            recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
         }
         if (endTime != null) {
            recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
         }
         if (secrecy != null) {
            recordInfoXml.append("<Secrecy> "+ secrecy + " </Secrecy>\r\n");
         }
         if (type != null) {
            // 大华NVR要求必须增加一个值为all的文本元素节点Type
            recordInfoXml.append("<Type>" + type+"</Type>\r\n");
         }
         recordInfoXml.append("</Query>\r\n");
         
         String tm = Long.toString(System.currentTimeMillis());
@@ -1221,7 +1252,7 @@
         Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),
               "z9hG4bK-ViaRecordInfo-" + tm, "fromRec" + tm, null, callIdHeader);
         transmitRequest(device, request, errorEvent);
         transmitRequest(device, request, errorEvent, okEvent);
      } catch (SipException | ParseException | InvalidArgumentException e) {
         e.printStackTrace();
         return false;
@@ -1501,7 +1532,7 @@
         // 有效时间默认为60秒以上
         Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm,
               "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog() + 60, "Catalog" ,
               "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" ,
               callIdHeader);
         transmitRequest(device, request, errorEvent, okEvent);
@@ -1589,7 +1620,7 @@
         content.append("PAUSE RTSP/1.0\r\n");
         content.append("CSeq: " + cseq + "\r\n");
         content.append("PauseTime: now\r\n");
         Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString(), cseq);
         Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
         if (request == null) {
            return;
         }
@@ -1620,7 +1651,7 @@
         content.append("PLAY RTSP/1.0\r\n");
         content.append("CSeq: " + cseq + "\r\n");
         content.append("Range: npt=now-\r\n");
         Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString(), cseq);
         Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
         if (request == null) return;
         logger.info(request.toString());
         ClientTransaction clientTransaction = null;
@@ -1649,7 +1680,7 @@
         content.append("CSeq: " + cseq + "\r\n");
         content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n");
         Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString(), cseq);
         Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
         if (request == null) return;
         logger.info(request.toString());
         ClientTransaction clientTransaction = null;
@@ -1677,7 +1708,7 @@
         content.append("PLAY RTSP/1.0\r\n");
         content.append("CSeq: " + cseq + "\r\n");
         content.append("Scale: " + String.format("%.1f",speed) + "\r\n");
         Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString(), cseq);
         Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
         if (request == null) return;
         logger.info(request.toString());
         ClientTransaction clientTransaction = null;