Kaynağa Gözat

收流时设置re_use_port参数解决端口关闭快速打开造成的端口未释放问题, 支持点播的tcp主动

648540858 2 yıl önce
ebeveyn
işleme
0f3898910c

+ 11 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java

@@ -247,6 +247,17 @@ public class Device {
 		return streamMode;
 	}
 
+	public Integer getStreamModeForParam() {
+		if (streamMode.equalsIgnoreCase("UDP")) {
+			return 0;
+		}else if (streamMode.equalsIgnoreCase("TCP-PASSIVE")) {
+			return 1;
+		}else if (streamMode.equalsIgnoreCase("TCP-ACTIVE")) {
+			return 2;
+		}
+		return 0;
+	}
+
 	public void setStreamMode(String streamMode) {
 		this.streamMode = streamMode;
 	}

+ 2 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java

@@ -425,7 +425,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
                     sendRtpItem.setApp("rtp");
                     if ("Playback".equalsIgnoreCase(sessionName)) {
                         sendRtpItem.setPlayType(InviteStreamType.PLAYBACK);
-                        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, device.isSsrcCheck(), true);
+                        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
                         sendRtpItem.setStreamId(ssrcInfo.getStream());
                         // 写入redis, 超时时回复
                         redisCatchStorage.updateSendRTPSever(sendRtpItem);
@@ -469,7 +469,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
                             if (mediaServerItem.isRtpEnable()) {
                                 streamId = String.format("%s_%s", device.getDeviceId(), channelId);
                             }
-                            SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false);
+                            SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false, 0, false, device.getStreamModeForParam());
                             logger.info(JSONObject.toJSONString(ssrcInfo));
                             sendRtpItem.setStreamId(ssrcInfo.getStream());
                             sendRtpItem.setSsrc(ssrc.equals(ssrcDefault) ? ssrcInfo.getSsrc() : ssrc);

+ 8 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java

@@ -346,4 +346,12 @@ public class ZLMRESTfulUtils {
         param.put("stream_id", streamId);
         return sendPost(mediaServerItem, "resumeRtpCheck",param, null);
     }
+
+    public JSONObject connectRtpServer(MediaServerItem mediaServerItem, String dst_url, int dst_port, String stream_id) {
+        Map<String, Object> param = new HashMap<>(1);
+        param.put("dst_url", dst_url);
+        param.put("dst_port", dst_port);
+        param.put("stream_id", stream_id);
+        return sendPost(mediaServerItem, "connectRtpServer",param, null);
+    }
 }

+ 19 - 3
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java

@@ -91,7 +91,17 @@ public class ZLMRTPServerFactory {
         return result;
     }
 
-    public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port) {
+    /**
+     * 开启rtpServer
+     * @param mediaServerItem zlm服务实例
+     * @param streamId 流Id
+     * @param ssrc ssrc
+     * @param port 端口, 0/null为使用随机
+     * @param reUsePort 是否重用端口
+     * @param tcpMode 0/null udp 模式,1 tcp 被动模式, 2 tcp 主动模式。
+     * @return
+     */
+    public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port, Boolean reUsePort, Integer tcpMode) {
         int result = -1;
         // 查询此rtp server 是否已经存在
         JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId);
@@ -107,7 +117,7 @@ public class ZLMRTPServerFactory {
                     JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(mediaServerItem, param);
                     if (jsonObject != null ) {
                         if (jsonObject.getInteger("code") == 0) {
-                            return createRTPServer(mediaServerItem, streamId, ssrc, port);
+                            return createRTPServer(mediaServerItem, streamId, ssrc, port, reUsePort, tcpMode);
                         }else {
                             logger.warn("[开启rtpServer], 重启RtpServer错误");
                         }
@@ -121,8 +131,14 @@ public class ZLMRTPServerFactory {
 
         Map<String, Object> param = new HashMap<>();
 
-        param.put("enable_tcp", 1);
+        if (tcpMode == null) {
+            tcpMode = 0;
+        }
+        param.put("tcp_mode", tcpMode);
         param.put("stream_id", streamId);
+        if (reUsePort != null) {
+            param.put("re_use_port", reUsePort?"1":"0");
+        }
         // 推流端口设置0则使用随机端口
         if (port == null) {
             param.put("port", 0);

+ 2 - 5
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java

@@ -44,11 +44,8 @@ public interface IMediaServerService {
 
     void updateVmServer(List<MediaServerItem>  mediaServerItemList);
 
-    SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback);
-
-    SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback);
-
-    SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback, Integer port);
+    SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck,
+                           boolean isPlayback, Integer port, Boolean reUsePort, Integer tcpMode);
 
     void closeRTPServer(MediaServerItem mediaServerItem, String streamId);
 

+ 3 - 11
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java

@@ -125,13 +125,10 @@ public class MediaServerServiceImpl implements IMediaServerService {
         }
     }
 
-    @Override
-    public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback) {
-        return openRTPServer(mediaServerItem, streamId, null, ssrcCheck,isPlayback);
-    }
 
     @Override
-    public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck, boolean isPlayback, Integer port) {
+    public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck,
+                                  boolean isPlayback, Integer port, Boolean reUsePort, Integer tcpMode) {
         if (mediaServerItem == null || mediaServerItem.getId() == null) {
             logger.info("[openRTPServer] 失败, mediaServerItem == null || mediaServerItem.getId() == null");
             return null;
@@ -153,18 +150,13 @@ public class MediaServerServiceImpl implements IMediaServerService {
         }
         int rtpServerPort;
         if (mediaServerItem.isRtpEnable()) {
-            rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port);
+            rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port, reUsePort, tcpMode);
         } else {
             rtpServerPort = mediaServerItem.getRtpProxyPort();
         }
         return new SSRCInfo(rtpServerPort, ssrc, streamId);
     }
 
-    @Override
-    public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback) {
-        return openRTPServer(mediaServerItem, streamId, ssrc, ssrcCheck, isPlayback, null);
-    }
-
     @Override
     public void closeRTPServer(MediaServerItem mediaServerItem, String streamId) {
         if (mediaServerItem == null) {

+ 31 - 8
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java

@@ -43,6 +43,7 @@ import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.util.ObjectUtils;
 
+import javax.sdp.*;
 import javax.sip.InvalidArgumentException;
 import javax.sip.ResponseEvent;
 import javax.sip.SipException;
@@ -51,6 +52,7 @@ import java.math.RoundingMode;
 import java.text.ParseException;
 import java.util.List;
 import java.util.UUID;
+import java.util.Vector;
 
 @SuppressWarnings(value = {"rawtypes", "unchecked"})
 @Service
@@ -180,7 +182,7 @@ public class PlayServiceImpl implements IPlayService {
             if (mediaServerItem.isRtpEnable()) {
                 streamId = String.format("%s_%s", device.getDeviceId(), channelId);
             }
-            SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false);
+            SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(),  false, 0, false, device.getStreamModeForParam());
             if (ssrcInfo == null) {
                 WVPResult wvpResult = new WVPResult();
                 wvpResult.setCode(ErrorCode.ERROR100.getCode());
@@ -296,6 +298,29 @@ public class PlayServiceImpl implements IPlayService {
                     String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim();
                     // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
                     if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
+                        if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
+                            String substring = contentString.substring(0, contentString.indexOf("y="));
+                            try {
+                                SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
+                                int port = -1;
+                                Vector mediaDescriptions = sdp.getMediaDescriptions(true);
+                                for (Object description : mediaDescriptions) {
+                                    MediaDescription mediaDescription = (MediaDescription) description;
+                                    Media media = mediaDescription.getMedia();
+
+                                    Vector mediaFormats = media.getMediaFormats(false);
+                                    if (mediaFormats.contains("96")) {
+                                        port = media.getMediaPort();
+                                        break;
+                                    }
+                                }
+                                logger.info("[点播-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
+                                JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
+                                logger.info("[点播-TCP主动连接对方] 结果: {}", jsonObject);
+                            } catch (SdpException e) {
+                                logger.error("[点播-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
+                            }
+                        }
                         return;
                     }
                     logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
@@ -331,7 +356,7 @@ public class PlayServiceImpl implements IPlayService {
                         mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{
                             if (result) {
                                 // 重新开启ssrc server
-                                mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, ssrcInfo.getPort());
+                                mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, ssrcInfo.getPort(), true, device.getStreamModeForParam());
                             }else {
                                 try {
                                     logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);
@@ -475,8 +500,7 @@ public class PlayServiceImpl implements IPlayService {
             return;
         }
         MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
-        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, device.isSsrcCheck(), true);
-
+        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(),  true, 0, false, device.getStreamModeForParam());
         playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback);
     }
 
@@ -595,7 +619,7 @@ public class PlayServiceImpl implements IPlayService {
                                     mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{
                                         if (result) {
                                             // 重新开启ssrc server
-                                            mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort());
+                                            mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort(), true, device.getStreamModeForParam());
                                         }else {
                                             try {
                                                 logger.warn("[回放消息]停止 {}/{}", device.getDeviceId(), channelId);
@@ -645,8 +669,7 @@ public class PlayServiceImpl implements IPlayService {
             playBackCallback.call(downloadResult);
             return;
         }
-        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, device.isSsrcCheck(), true);
-
+        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(),  true, 0, false, device.getStreamModeForParam());
         download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, infoCallBack, playBackCallback);
     }
 
@@ -755,7 +778,7 @@ public class PlayServiceImpl implements IPlayService {
                                     mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{
                                         if (result) {
                                             // 重新开启ssrc server
-                                            mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort());
+                                            mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort(), true, device.getStreamModeForParam());
                                         }else {
                                             try {
                                                 logger.warn("[录像下载] 停止{}/{}", device.getDeviceId(), channelId);

+ 3 - 1
web_src/src/components/DeviceList.vue

@@ -25,11 +25,13 @@
       </el-table-column>
       <el-table-column prop="manufacturer" label="厂家" min-width="120" >
       </el-table-column>
+      <el-table-column prop="transport" label="信令传输模式" min-width="120" >
+      </el-table-column>
       <el-table-column label="流传输模式"  min-width="160" >
         <template slot-scope="scope">
           <el-select size="mini" @change="transportChange(scope.row)" v-model="scope.row.streamMode" placeholder="请选择" style="width: 120px">
             <el-option key="UDP" label="UDP" value="UDP"></el-option>
-            <el-option key="TCP-ACTIVE" label="TCP主动模式" :disabled="true" value="TCP-ACTIVE"></el-option>
+            <el-option key="TCP-ACTIVE" label="TCP主动模式"  value="TCP-ACTIVE"></el-option>
             <el-option key="TCP-PASSIVE" label="TCP被动模式" value="TCP-PASSIVE"></el-option>
           </el-select>
         </template>