Commit 0f3898910c42d4303347ac7295d3c7f0cc8e8457

Authored by 648540858
1 parent f68f6d20

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

src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
@@ -247,6 +247,17 @@ public class Device { @@ -247,6 +247,17 @@ public class Device {
247 return streamMode; 247 return streamMode;
248 } 248 }
249 249
  250 + public Integer getStreamModeForParam() {
  251 + if (streamMode.equalsIgnoreCase("UDP")) {
  252 + return 0;
  253 + }else if (streamMode.equalsIgnoreCase("TCP-PASSIVE")) {
  254 + return 1;
  255 + }else if (streamMode.equalsIgnoreCase("TCP-ACTIVE")) {
  256 + return 2;
  257 + }
  258 + return 0;
  259 + }
  260 +
250 public void setStreamMode(String streamMode) { 261 public void setStreamMode(String streamMode) {
251 this.streamMode = streamMode; 262 this.streamMode = streamMode;
252 } 263 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -425,7 +425,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -425,7 +425,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
425 sendRtpItem.setApp("rtp"); 425 sendRtpItem.setApp("rtp");
426 if ("Playback".equalsIgnoreCase(sessionName)) { 426 if ("Playback".equalsIgnoreCase(sessionName)) {
427 sendRtpItem.setPlayType(InviteStreamType.PLAYBACK); 427 sendRtpItem.setPlayType(InviteStreamType.PLAYBACK);
428 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, device.isSsrcCheck(), true); 428 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
429 sendRtpItem.setStreamId(ssrcInfo.getStream()); 429 sendRtpItem.setStreamId(ssrcInfo.getStream());
430 // 写入redis, 超时时回复 430 // 写入redis, 超时时回复
431 redisCatchStorage.updateSendRTPSever(sendRtpItem); 431 redisCatchStorage.updateSendRTPSever(sendRtpItem);
@@ -469,7 +469,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -469,7 +469,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
469 if (mediaServerItem.isRtpEnable()) { 469 if (mediaServerItem.isRtpEnable()) {
470 streamId = String.format("%s_%s", device.getDeviceId(), channelId); 470 streamId = String.format("%s_%s", device.getDeviceId(), channelId);
471 } 471 }
472 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false); 472 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false, 0, false, device.getStreamModeForParam());
473 logger.info(JSONObject.toJSONString(ssrcInfo)); 473 logger.info(JSONObject.toJSONString(ssrcInfo));
474 sendRtpItem.setStreamId(ssrcInfo.getStream()); 474 sendRtpItem.setStreamId(ssrcInfo.getStream());
475 sendRtpItem.setSsrc(ssrc.equals(ssrcDefault) ? ssrcInfo.getSsrc() : ssrc); 475 sendRtpItem.setSsrc(ssrc.equals(ssrcDefault) ? ssrcInfo.getSsrc() : ssrc);
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -346,4 +346,12 @@ public class ZLMRESTfulUtils { @@ -346,4 +346,12 @@ public class ZLMRESTfulUtils {
346 param.put("stream_id", streamId); 346 param.put("stream_id", streamId);
347 return sendPost(mediaServerItem, "resumeRtpCheck",param, null); 347 return sendPost(mediaServerItem, "resumeRtpCheck",param, null);
348 } 348 }
  349 +
  350 + public JSONObject connectRtpServer(MediaServerItem mediaServerItem, String dst_url, int dst_port, String stream_id) {
  351 + Map<String, Object> param = new HashMap<>(1);
  352 + param.put("dst_url", dst_url);
  353 + param.put("dst_port", dst_port);
  354 + param.put("stream_id", stream_id);
  355 + return sendPost(mediaServerItem, "connectRtpServer",param, null);
  356 + }
349 } 357 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -91,7 +91,17 @@ public class ZLMRTPServerFactory { @@ -91,7 +91,17 @@ public class ZLMRTPServerFactory {
91 return result; 91 return result;
92 } 92 }
93 93
94 - public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port) { 94 + /**
  95 + * 开启rtpServer
  96 + * @param mediaServerItem zlm服务实例
  97 + * @param streamId 流Id
  98 + * @param ssrc ssrc
  99 + * @param port 端口, 0/null为使用随机
  100 + * @param reUsePort 是否重用端口
  101 + * @param tcpMode 0/null udp 模式,1 tcp 被动模式, 2 tcp 主动模式。
  102 + * @return
  103 + */
  104 + public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port, Boolean reUsePort, Integer tcpMode) {
95 int result = -1; 105 int result = -1;
96 // 查询此rtp server 是否已经存在 106 // 查询此rtp server 是否已经存在
97 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId); 107 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId);
@@ -107,7 +117,7 @@ public class ZLMRTPServerFactory { @@ -107,7 +117,7 @@ public class ZLMRTPServerFactory {
107 JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(mediaServerItem, param); 117 JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(mediaServerItem, param);
108 if (jsonObject != null ) { 118 if (jsonObject != null ) {
109 if (jsonObject.getInteger("code") == 0) { 119 if (jsonObject.getInteger("code") == 0) {
110 - return createRTPServer(mediaServerItem, streamId, ssrc, port); 120 + return createRTPServer(mediaServerItem, streamId, ssrc, port, reUsePort, tcpMode);
111 }else { 121 }else {
112 logger.warn("[开启rtpServer], 重启RtpServer错误"); 122 logger.warn("[开启rtpServer], 重启RtpServer错误");
113 } 123 }
@@ -121,8 +131,14 @@ public class ZLMRTPServerFactory { @@ -121,8 +131,14 @@ public class ZLMRTPServerFactory {
121 131
122 Map<String, Object> param = new HashMap<>(); 132 Map<String, Object> param = new HashMap<>();
123 133
124 - param.put("enable_tcp", 1); 134 + if (tcpMode == null) {
  135 + tcpMode = 0;
  136 + }
  137 + param.put("tcp_mode", tcpMode);
125 param.put("stream_id", streamId); 138 param.put("stream_id", streamId);
  139 + if (reUsePort != null) {
  140 + param.put("re_use_port", reUsePort?"1":"0");
  141 + }
126 // 推流端口设置0则使用随机端口 142 // 推流端口设置0则使用随机端口
127 if (port == null) { 143 if (port == null) {
128 param.put("port", 0); 144 param.put("port", 0);
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
@@ -44,11 +44,8 @@ public interface IMediaServerService { @@ -44,11 +44,8 @@ public interface IMediaServerService {
44 44
45 void updateVmServer(List<MediaServerItem> mediaServerItemList); 45 void updateVmServer(List<MediaServerItem> mediaServerItemList);
46 46
47 - SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback);  
48 -  
49 - SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback);  
50 -  
51 - SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback, Integer port); 47 + SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck,
  48 + boolean isPlayback, Integer port, Boolean reUsePort, Integer tcpMode);
52 49
53 void closeRTPServer(MediaServerItem mediaServerItem, String streamId); 50 void closeRTPServer(MediaServerItem mediaServerItem, String streamId);
54 51
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -125,13 +125,10 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -125,13 +125,10 @@ public class MediaServerServiceImpl implements IMediaServerService {
125 } 125 }
126 } 126 }
127 127
128 - @Override  
129 - public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback) {  
130 - return openRTPServer(mediaServerItem, streamId, null, ssrcCheck,isPlayback);  
131 - }  
132 128
133 @Override 129 @Override
134 - public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck, boolean isPlayback, Integer port) { 130 + public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck,
  131 + boolean isPlayback, Integer port, Boolean reUsePort, Integer tcpMode) {
135 if (mediaServerItem == null || mediaServerItem.getId() == null) { 132 if (mediaServerItem == null || mediaServerItem.getId() == null) {
136 logger.info("[openRTPServer] 失败, mediaServerItem == null || mediaServerItem.getId() == null"); 133 logger.info("[openRTPServer] 失败, mediaServerItem == null || mediaServerItem.getId() == null");
137 return null; 134 return null;
@@ -153,7 +150,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -153,7 +150,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
153 } 150 }
154 int rtpServerPort; 151 int rtpServerPort;
155 if (mediaServerItem.isRtpEnable()) { 152 if (mediaServerItem.isRtpEnable()) {
156 - rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port); 153 + rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port, reUsePort, tcpMode);
157 } else { 154 } else {
158 rtpServerPort = mediaServerItem.getRtpProxyPort(); 155 rtpServerPort = mediaServerItem.getRtpProxyPort();
159 } 156 }
@@ -161,11 +158,6 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -161,11 +158,6 @@ public class MediaServerServiceImpl implements IMediaServerService {
161 } 158 }
162 159
163 @Override 160 @Override
164 - public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback) {  
165 - return openRTPServer(mediaServerItem, streamId, ssrc, ssrcCheck, isPlayback, null);  
166 - }  
167 -  
168 - @Override  
169 public void closeRTPServer(MediaServerItem mediaServerItem, String streamId) { 161 public void closeRTPServer(MediaServerItem mediaServerItem, String streamId) {
170 if (mediaServerItem == null) { 162 if (mediaServerItem == null) {
171 return; 163 return;
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -43,6 +43,7 @@ import org.springframework.data.redis.core.RedisTemplate; @@ -43,6 +43,7 @@ import org.springframework.data.redis.core.RedisTemplate;
43 import org.springframework.stereotype.Service; 43 import org.springframework.stereotype.Service;
44 import org.springframework.util.ObjectUtils; 44 import org.springframework.util.ObjectUtils;
45 45
  46 +import javax.sdp.*;
46 import javax.sip.InvalidArgumentException; 47 import javax.sip.InvalidArgumentException;
47 import javax.sip.ResponseEvent; 48 import javax.sip.ResponseEvent;
48 import javax.sip.SipException; 49 import javax.sip.SipException;
@@ -51,6 +52,7 @@ import java.math.RoundingMode; @@ -51,6 +52,7 @@ import java.math.RoundingMode;
51 import java.text.ParseException; 52 import java.text.ParseException;
52 import java.util.List; 53 import java.util.List;
53 import java.util.UUID; 54 import java.util.UUID;
  55 +import java.util.Vector;
54 56
55 @SuppressWarnings(value = {"rawtypes", "unchecked"}) 57 @SuppressWarnings(value = {"rawtypes", "unchecked"})
56 @Service 58 @Service
@@ -180,7 +182,7 @@ public class PlayServiceImpl implements IPlayService { @@ -180,7 +182,7 @@ public class PlayServiceImpl implements IPlayService {
180 if (mediaServerItem.isRtpEnable()) { 182 if (mediaServerItem.isRtpEnable()) {
181 streamId = String.format("%s_%s", device.getDeviceId(), channelId); 183 streamId = String.format("%s_%s", device.getDeviceId(), channelId);
182 } 184 }
183 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false); 185 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false, 0, false, device.getStreamModeForParam());
184 if (ssrcInfo == null) { 186 if (ssrcInfo == null) {
185 WVPResult wvpResult = new WVPResult(); 187 WVPResult wvpResult = new WVPResult();
186 wvpResult.setCode(ErrorCode.ERROR100.getCode()); 188 wvpResult.setCode(ErrorCode.ERROR100.getCode());
@@ -296,6 +298,29 @@ public class PlayServiceImpl implements IPlayService { @@ -296,6 +298,29 @@ public class PlayServiceImpl implements IPlayService {
296 String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim(); 298 String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim();
297 // 查询到ssrc不一致且开启了ssrc校验则需要针对处理 299 // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
298 if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { 300 if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
  301 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
  302 + String substring = contentString.substring(0, contentString.indexOf("y="));
  303 + try {
  304 + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
  305 + int port = -1;
  306 + Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  307 + for (Object description : mediaDescriptions) {
  308 + MediaDescription mediaDescription = (MediaDescription) description;
  309 + Media media = mediaDescription.getMedia();
  310 +
  311 + Vector mediaFormats = media.getMediaFormats(false);
  312 + if (mediaFormats.contains("96")) {
  313 + port = media.getMediaPort();
  314 + break;
  315 + }
  316 + }
  317 + logger.info("[点播-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  318 + JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
  319 + logger.info("[点播-TCP主动连接对方] 结果: {}", jsonObject);
  320 + } catch (SdpException e) {
  321 + logger.error("[点播-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
  322 + }
  323 + }
299 return; 324 return;
300 } 325 }
301 logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse); 326 logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
@@ -331,7 +356,7 @@ public class PlayServiceImpl implements IPlayService { @@ -331,7 +356,7 @@ public class PlayServiceImpl implements IPlayService {
331 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{ 356 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{
332 if (result) { 357 if (result) {
333 // 重新开启ssrc server 358 // 重新开启ssrc server
334 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, ssrcInfo.getPort()); 359 + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, ssrcInfo.getPort(), true, device.getStreamModeForParam());
335 }else { 360 }else {
336 try { 361 try {
337 logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId); 362 logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);
@@ -475,8 +500,7 @@ public class PlayServiceImpl implements IPlayService { @@ -475,8 +500,7 @@ public class PlayServiceImpl implements IPlayService {
475 return; 500 return;
476 } 501 }
477 MediaServerItem newMediaServerItem = getNewMediaServerItem(device); 502 MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
478 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, device.isSsrcCheck(), true);  
479 - 503 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
480 playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback); 504 playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback);
481 } 505 }
482 506
@@ -595,7 +619,7 @@ public class PlayServiceImpl implements IPlayService { @@ -595,7 +619,7 @@ public class PlayServiceImpl implements IPlayService {
595 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{ 619 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{
596 if (result) { 620 if (result) {
597 // 重新开启ssrc server 621 // 重新开启ssrc server
598 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort()); 622 + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort(), true, device.getStreamModeForParam());
599 }else { 623 }else {
600 try { 624 try {
601 logger.warn("[回放消息]停止 {}/{}", device.getDeviceId(), channelId); 625 logger.warn("[回放消息]停止 {}/{}", device.getDeviceId(), channelId);
@@ -645,8 +669,7 @@ public class PlayServiceImpl implements IPlayService { @@ -645,8 +669,7 @@ public class PlayServiceImpl implements IPlayService {
645 playBackCallback.call(downloadResult); 669 playBackCallback.call(downloadResult);
646 return; 670 return;
647 } 671 }
648 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, device.isSsrcCheck(), true);  
649 - 672 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
650 download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, infoCallBack, playBackCallback); 673 download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, infoCallBack, playBackCallback);
651 } 674 }
652 675
@@ -755,7 +778,7 @@ public class PlayServiceImpl implements IPlayService { @@ -755,7 +778,7 @@ public class PlayServiceImpl implements IPlayService {
755 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{ 778 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{
756 if (result) { 779 if (result) {
757 // 重新开启ssrc server 780 // 重新开启ssrc server
758 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort()); 781 + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort(), true, device.getStreamModeForParam());
759 }else { 782 }else {
760 try { 783 try {
761 logger.warn("[录像下载] 停止{}/{}", device.getDeviceId(), channelId); 784 logger.warn("[录像下载] 停止{}/{}", device.getDeviceId(), channelId);
web_src/src/components/DeviceList.vue
@@ -25,11 +25,13 @@ @@ -25,11 +25,13 @@
25 </el-table-column> 25 </el-table-column>
26 <el-table-column prop="manufacturer" label="厂家" min-width="120" > 26 <el-table-column prop="manufacturer" label="厂家" min-width="120" >
27 </el-table-column> 27 </el-table-column>
  28 + <el-table-column prop="transport" label="信令传输模式" min-width="120" >
  29 + </el-table-column>
28 <el-table-column label="流传输模式" min-width="160" > 30 <el-table-column label="流传输模式" min-width="160" >
29 <template slot-scope="scope"> 31 <template slot-scope="scope">
30 <el-select size="mini" @change="transportChange(scope.row)" v-model="scope.row.streamMode" placeholder="请选择" style="width: 120px"> 32 <el-select size="mini" @change="transportChange(scope.row)" v-model="scope.row.streamMode" placeholder="请选择" style="width: 120px">
31 <el-option key="UDP" label="UDP" value="UDP"></el-option> 33 <el-option key="UDP" label="UDP" value="UDP"></el-option>
32 - <el-option key="TCP-ACTIVE" label="TCP主动模式" :disabled="true" value="TCP-ACTIVE"></el-option> 34 + <el-option key="TCP-ACTIVE" label="TCP主动模式" value="TCP-ACTIVE"></el-option>
33 <el-option key="TCP-PASSIVE" label="TCP被动模式" value="TCP-PASSIVE"></el-option> 35 <el-option key="TCP-PASSIVE" label="TCP被动模式" value="TCP-PASSIVE"></el-option>
34 </el-select> 36 </el-select>
35 </template> 37 </template>