648540858
2022-03-17 59ef6e67d3a1357c19039527dac47747e2ac20fe
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,8 +336,9 @@
     * @param errorEvent sip错误订阅
     */
   @Override
   public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
      String streamId = ssrcInfo.getStreamId();
   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;
         String streamMode = device.getStreamMode().toUpperCase();
@@ -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);
@@ -404,6 +412,8 @@
         }
         content.append("y="+ssrcInfo.getSsrc()+"\r\n");//ssrc
         // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
//         content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备
         String tm = Long.toString(System.currentTimeMillis());
@@ -412,14 +422,14 @@
         Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrcInfo.getSsrc(), callIdHeader);
         String finalStreamId = streamId;
         transmitRequest(device, request, (e -> {
            streamSession.remove(device.getDeviceId(), channelId);
            mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc());
            streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
            mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
            errorEvent.response(e);
         }), e ->{
            streamSession.put(device.getDeviceId(), channelId ,ssrcInfo.getSsrc(), finalStreamId, mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction());
            streamSession.put(device.getDeviceId(), channelId , e.dialog);
            // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
            streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction());
            streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog);
         });
         
@@ -437,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.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
         // 添加订阅
         JSONObject subscribeKey = new JSONObject();
         subscribeKey.put("app", "rtp");
         subscribeKey.put("stream", ssrcInfo.getStreamId());
         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);
         });
         logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
         StringBuffer content = new StringBuffer(200);
           content.append("v=0\r\n");
@@ -465,8 +462,6 @@
           content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
           content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
               +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
         String streamMode = device.getStreamMode().toUpperCase();
@@ -523,13 +518,31 @@
         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 -> {
            ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
              streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), responseEvent.getClientTransaction());
            streamSession.put(device.getDeviceId(), channelId, okEvent.dialog);
              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.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
         // 添加订阅
         JSONObject subscribeKey = new JSONObject();
         subscribeKey.put("app", "rtp");
         subscribeKey.put("stream", ssrcInfo.getStreamId());
         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);
         });
         logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
         StringBuffer content = new StringBuffer(200);
           content.append("v=0\r\n");
@@ -631,10 +630,24 @@
         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);
           streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), transaction);
           streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), transaction);
           streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), transaction);
      } catch ( SipException | ParseException | InvalidArgumentException e) {
         e.printStackTrace();
@@ -645,17 +658,19 @@
    * 视频流停止, 不使用回调
    */
   @Override
   public void streamByeCmd(String deviceId, String channelId) {
      streamByeCmd(deviceId, channelId, 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, SipSubscribe.Event okEvent) {
   public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) {
      try {
         ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId);
         SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, null, stream);
         ClientTransaction transaction = streamSession.getTransactionByStream(deviceId, channelId, stream);
         if (transaction == null) {
            logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
            SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>();
@@ -664,7 +679,20 @@
            }
            return;
         }
         SIPDialog dialog = streamSession.getDialog(deviceId, channelId);
         SIPDialog dialog;
         if (callId != null) {
            dialog = streamSession.getDialogByCallId(deviceId, channelId, callId);
         }else {
            if (stream == null) return;
            dialog = streamSession.getDialogByStream(deviceId, channelId, stream);
         }
         if (ssrcTransaction != null) {
            MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
            mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc());
            mediaServerService.closeRTPServer(deviceId, channelId, ssrcTransaction.getStream());
            streamSession.remove(deviceId, channelId, ssrcTransaction.getStream());
         }
         if (dialog == null) {
            logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId);
            return;
@@ -708,12 +736,6 @@
         dialog.sendRequest(clientTransaction);
         SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId);
         if (ssrcTransaction != null) {
            MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
            mediaServerService.releaseSsrc(mediaServerItem, ssrcTransaction.getSsrc());
            streamSession.remove(deviceId, channelId);
         }
      } catch (SipException | ParseException e) {
         e.printStackTrace();
      }
@@ -1098,8 +1120,9 @@
   @Override
   public boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) {
      try {
         String charset = device.getCharset();
         StringBuffer catalogXml = new StringBuffer(200);
         catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
         catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
         catalogXml.append("<Query>\r\n");
         catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n");
         catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
@@ -1131,7 +1154,8 @@
   public boolean deviceInfoQuery(Device device) {
      try {
         StringBuffer catalogXml = new StringBuffer(200);
         catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
         String charset = device.getCharset();
         catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
         catalogXml.append("<Query>\r\n");
         catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
         catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
@@ -1161,11 +1185,10 @@
    */ 
   @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");
         String charset = device.getCharset();
         catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
         catalogXml.append("<Query>\r\n");
         catalogXml.append("<CmdType>Catalog</CmdType>\r\n");
         catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
@@ -1195,21 +1218,34 @@
    * @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");
         String charset = device.getCharset();
         recordInfoXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
         recordInfoXml.append("<Query>\r\n");
         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());
@@ -1220,7 +1256,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;
@@ -1364,7 +1400,8 @@
   public boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) {
      try {
         StringBuffer mobilePostitionXml = new StringBuffer(200);
         mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
         String charset = device.getCharset();
         mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
         mobilePostitionXml.append("<Query>\r\n");
         mobilePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
         mobilePostitionXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
@@ -1399,7 +1436,8 @@
   public boolean mobilePositionSubscribe(Device device, int expires, int interval) {
      try {
         StringBuffer subscribePostitionXml = new StringBuffer(200);
         subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
         String charset = device.getCharset();
         subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
         subscribePostitionXml.append("<Query>\r\n");
         subscribePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
         subscribePostitionXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
@@ -1441,7 +1479,8 @@
   public boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime) {
      try {
         StringBuffer cmdXml = new StringBuffer(200);
         cmdXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
         String charset = device.getCharset();
         cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
         cmdXml.append("<Query>\r\n");
         cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
         cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
@@ -1486,7 +1525,8 @@
   public boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
      try {
         StringBuffer cmdXml = new StringBuffer(200);
         cmdXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
         String charset = device.getCharset();
         cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
         cmdXml.append("<Query>\r\n");
         cmdXml.append("<CmdType>Catalog</CmdType>\r\n");
         cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
@@ -1498,7 +1538,10 @@
         CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
               : udpSipProvider.getNewCallId();
         Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" , callIdHeader);
         // 有效时间默认为60秒以上
         Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm,
               "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" ,
               callIdHeader);
         transmitRequest(device, request, errorEvent, okEvent);
         return true;
@@ -1585,7 +1628,10 @@
         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;
         }
         logger.info(request.toString());
         ClientTransaction clientTransaction = null;
         if ("TCP".equals(device.getTransport())) {
@@ -1613,7 +1659,8 @@
         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;
         if ("TCP".equals(device.getTransport())) {
@@ -1641,7 +1688,8 @@
         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;
         if ("TCP".equals(device.getTransport())) {
@@ -1668,7 +1716,8 @@
         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;
         if ("TCP".equals(device.getTransport())) {