Commit d48f89eee40c58b2f0b69aaf4d7fab469dc4657b

Authored by 648540858
1 parent 0cb68938

修复端口分配的并发问题

src/main/java/com/genersoft/iot/vmp/common/CommonGbChannel.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +
  5 +public class CommonGbChannel {
  6 +
  7 + /**
  8 + * 国标字段:归属
  9 + */
  10 + @Schema(description = "归属")
  11 + private String owner;
  12 +
  13 + /**
  14 + * 国标字段:行政区划
  15 + */
  16 + @Schema(description = "行政区划")
  17 + private String civilCode;
  18 +
  19 + /**
  20 + * 国标字段:安装地址
  21 + */
  22 + @Schema(description = "安装地址")
  23 + private String address;
  24 +
  25 + /**
  26 + * 国标字段:经度
  27 + */
  28 + @Schema(description = "经度")
  29 + private Double longitude;
  30 +
  31 + /**
  32 + * 国标字段:纬度
  33 + */
  34 + @Schema(description = "纬度")
  35 + private Double latitude;
  36 +
  37 + /**
  38 + * 国标字段:摄像机类型:
  39 + * 1-球机;
  40 + * 2-半球;
  41 + * 3-固定枪机;
  42 + * 4-遥控枪机
  43 + */
  44 + @Schema(description = "摄像机类型")
  45 + private Integer ptzType;
  46 +
  47 + /**
  48 + * 国标字段:摄像机位置类型扩展。
  49 + * 1-省际检查站、
  50 + * 2-党政机关、
  51 + * 3-车站码头、
  52 + * 4-中心广场、
  53 + * 5-体育场馆、
  54 + * 6-商业中心、
  55 + * 7-宗教场所、
  56 + * 8-校园周边、
  57 + * 9-治安复杂区域、
  58 + * 10-交通干线
  59 + */
  60 + @Schema(description = "摄像机位置类型扩展")
  61 + private Integer positionType;
  62 +
  63 + /**
  64 + * 国标字段:安装位置室外、室内属性
  65 + * 1-室外、
  66 + * 2-室内
  67 + */
  68 + @Schema(description = "安装位置室外、室内属性")
  69 + private Integer roomType;
  70 +
  71 + /**
  72 + * 国标字段:用途
  73 + * 1-治安、
  74 + * 2-交通、
  75 + * 3-重点、
  76 + */
  77 + @Schema(description = "用途")
  78 + private Integer useType;
  79 +
  80 + /**
  81 + * 国标字段:补光属性
  82 + * 1-无补光、
  83 + * 2-红外补光、
  84 + * 3-白光补光
  85 + */
  86 + @Schema(description = "补光属性")
  87 + private Integer supplyLightType;
  88 +
  89 + /**
  90 + * 摄像机监视方位属性。
  91 + * 1-东、
  92 + * 2-西、
  93 + * 3-南、
  94 + * 4-北、
  95 + * 5-东南、
  96 + * 6-东北、
  97 + * 7-西南、
  98 + * 8-西北
  99 + *
  100 + */
  101 + @Schema(description = "方位")
  102 + private Integer directionType;
  103 +
  104 + public String getOwner() {
  105 + return owner;
  106 + }
  107 +
  108 + public void setOwner(String owner) {
  109 + this.owner = owner;
  110 + }
  111 +
  112 + public String getCivilCode() {
  113 + return civilCode;
  114 + }
  115 +
  116 + public void setCivilCode(String civilCode) {
  117 + this.civilCode = civilCode;
  118 + }
  119 +
  120 + public String getAddress() {
  121 + return address;
  122 + }
  123 +
  124 + public void setAddress(String address) {
  125 + this.address = address;
  126 + }
  127 +
  128 + public Double getLongitude() {
  129 + return longitude;
  130 + }
  131 +
  132 + public void setLongitude(Double longitude) {
  133 + this.longitude = longitude;
  134 + }
  135 +
  136 + public Double getLatitude() {
  137 + return latitude;
  138 + }
  139 +
  140 + public void setLatitude(Double latitude) {
  141 + this.latitude = latitude;
  142 + }
  143 +
  144 + public Integer getPtzType() {
  145 + return ptzType;
  146 + }
  147 +
  148 + public void setPtzType(Integer ptzType) {
  149 + this.ptzType = ptzType;
  150 + }
  151 +
  152 + public Integer getPositionType() {
  153 + return positionType;
  154 + }
  155 +
  156 + public void setPositionType(Integer positionType) {
  157 + this.positionType = positionType;
  158 + }
  159 +
  160 + public Integer getRoomType() {
  161 + return roomType;
  162 + }
  163 +
  164 + public void setRoomType(Integer roomType) {
  165 + this.roomType = roomType;
  166 + }
  167 +
  168 + public Integer getUseType() {
  169 + return useType;
  170 + }
  171 +
  172 + public void setUseType(Integer useType) {
  173 + this.useType = useType;
  174 + }
  175 +
  176 + public Integer getSupplyLightType() {
  177 + return supplyLightType;
  178 + }
  179 +
  180 + public void setSupplyLightType(Integer supplyLightType) {
  181 + this.supplyLightType = supplyLightType;
  182 + }
  183 +
  184 + public Integer getDirectionType() {
  185 + return directionType;
  186 + }
  187 +
  188 + public void setDirectionType(Integer directionType) {
  189 + this.directionType = directionType;
  190 + }
  191 +}
src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java
@@ -3,12 +3,14 @@ package com.genersoft.iot.vmp.media.zlm; @@ -3,12 +3,14 @@ package com.genersoft.iot.vmp.media.zlm;
3 import com.genersoft.iot.vmp.common.VideoManagerConstants; 3 import com.genersoft.iot.vmp.common.VideoManagerConstants;
4 import com.genersoft.iot.vmp.conf.UserSetting; 4 import com.genersoft.iot.vmp.conf.UserSetting;
5 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; 5 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
6 -import com.genersoft.iot.vmp.media.zlm.dto.MediaSendRtpPortInfo; 6 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
7 import com.genersoft.iot.vmp.utils.redis.RedisUtil; 7 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  8 +import org.apache.commons.lang3.math.NumberUtils;
8 import org.slf4j.Logger; 9 import org.slf4j.Logger;
9 import org.slf4j.LoggerFactory; 10 import org.slf4j.LoggerFactory;
10 import org.springframework.beans.factory.annotation.Autowired; 11 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.data.redis.core.RedisTemplate; 12 import org.springframework.data.redis.core.RedisTemplate;
  13 +import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
12 import org.springframework.stereotype.Component; 14 import org.springframework.stereotype.Component;
13 15
14 import java.util.HashMap; 16 import java.util.HashMap;
@@ -26,23 +28,14 @@ public class SendRtpPortManager { @@ -26,23 +28,14 @@ public class SendRtpPortManager {
26 @Autowired 28 @Autowired
27 private RedisTemplate<Object, Object> redisTemplate; 29 private RedisTemplate<Object, Object> redisTemplate;
28 30
29 - private final String KEY = "VM_MEDIA_SEND_RTP_PORT_RANGE_"; 31 + private final String KEY = "VM_MEDIA_SEND_RTP_PORT_";
30 32
31 -  
32 - public void initServerPort(String mediaServerId, int startPort, int endPort){  
33 - String key = KEY + userSetting.getServerId() + "_" + mediaServerId;  
34 - MediaSendRtpPortInfo mediaSendRtpPortInfo = new MediaSendRtpPortInfo(startPort, endPort, mediaServerId);  
35 - redisTemplate.opsForValue().set(key, mediaSendRtpPortInfo);  
36 - }  
37 -  
38 - public int getNextPort(String mediaServerId) {  
39 - String sendIndexKey = KEY + userSetting.getServerId() + "_" + mediaServerId;  
40 - MediaSendRtpPortInfo mediaSendRtpPortInfo = (MediaSendRtpPortInfo)redisTemplate.opsForValue().get(sendIndexKey);  
41 - if (mediaSendRtpPortInfo == null) {  
42 - logger.warn("[发送端口管理] 获取{}的发送端口时未找到端口信息", mediaServerId);  
43 - return 0; 33 + public int getNextPort(MediaServerItem mediaServer) {
  34 + if (mediaServer == null) {
  35 + logger.warn("[发送端口管理] 参数错误,mediaServer为NULL");
  36 + return -1;
44 } 37 }
45 - 38 + String sendIndexKey = KEY + userSetting.getServerId() + "_" + mediaServer.getId();
46 String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX 39 String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX
47 + userSetting.getServerId() + "_*"; 40 + userSetting.getServerId() + "_*";
48 List<Object> queryResult = RedisUtil.scan(redisTemplate, key); 41 List<Object> queryResult = RedisUtil.scan(redisTemplate, key);
@@ -54,14 +47,39 @@ public class SendRtpPortManager { @@ -54,14 +47,39 @@ public class SendRtpPortManager {
54 sendRtpItemMap.put(sendRtpItem.getLocalPort(), sendRtpItem); 47 sendRtpItemMap.put(sendRtpItem.getLocalPort(), sendRtpItem);
55 } 48 }
56 } 49 }
  50 + String sendRtpPortRange = mediaServer.getSendRtpPortRange();
  51 + int startPort;
  52 + int endPort;
  53 + if (sendRtpPortRange == null) {
  54 + logger.warn("{}未设置发送端口默认值,自动使用40000-50000作为端口范围", mediaServer.getId());
  55 + String[] portArray = sendRtpPortRange.split(",");
  56 + if (portArray.length != 2 || !NumberUtils.isParsable(portArray[0]) || !NumberUtils.isParsable(portArray[1])) {
  57 + logger.warn("{}发送端口配置格式错误,自动使用40000-50000作为端口范围", mediaServer.getId());
  58 + startPort = 50000;
  59 + endPort = 60000;
  60 + }else {
57 61
58 - int port = getPort(mediaSendRtpPortInfo.getCurrent(),  
59 - mediaSendRtpPortInfo.getStart(),  
60 - mediaSendRtpPortInfo.getEnd(), checkPort -> sendRtpItemMap.get(checkPort) == null);  
61 -  
62 - mediaSendRtpPortInfo.setCurrent(port);  
63 - redisTemplate.opsForValue().set(sendIndexKey, mediaSendRtpPortInfo);  
64 - return port; 62 + if ( Integer.parseInt(portArray[1]) - Integer.parseInt(portArray[0]) < 1) {
  63 + logger.warn("{}发送端口配置错误,结束端口至少比开始端口大一,自动使用40000-50000作为端口范围", mediaServer.getId());
  64 + startPort = 50000;
  65 + endPort = 60000;
  66 + }else {
  67 + startPort = Integer.parseInt(portArray[0]);
  68 + endPort = Integer.parseInt(portArray[1]);
  69 + }
  70 + }
  71 + }else {
  72 + startPort = 50000;
  73 + endPort = 60000;
  74 + }
  75 + if (redisTemplate == null || redisTemplate.getConnectionFactory() == null) {
  76 + logger.warn("{}获取redis连接信息失败", mediaServer.getId());
  77 + return -1;
  78 + }
  79 + RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(sendIndexKey , redisTemplate.getConnectionFactory());
  80 + return redisAtomicInteger.getAndUpdate((current)->{
  81 + return getPort(current, startPort, endPort, checkPort-> !sendRtpItemMap.containsKey(checkPort));
  82 + });
65 } 83 }
66 84
67 interface CheckPortCallback{ 85 interface CheckPortCallback{
@@ -69,22 +87,25 @@ public class SendRtpPortManager { @@ -69,22 +87,25 @@ public class SendRtpPortManager {
69 } 87 }
70 88
71 private int getPort(int current, int start, int end, CheckPortCallback checkPortCallback) { 89 private int getPort(int current, int start, int end, CheckPortCallback checkPortCallback) {
72 - int port;  
73 - if (current %2 != 0) {  
74 - port = current + 1;  
75 - }else {  
76 - port = current + 2;  
77 - }  
78 - if (port > end) {  
79 - if (start %2 != 0) {  
80 - port = start + 1; 90 + if (current <= 0) {
  91 + if (start%2 == 0) {
  92 + current = start;
81 }else { 93 }else {
82 - port = start; 94 + current = start + 1;
  95 + }
  96 + }else {
  97 + current += 2;
  98 + if (current > end) {
  99 + if (start%2 == 0) {
  100 + current = start;
  101 + }else {
  102 + current = start + 1;
  103 + }
83 } 104 }
84 } 105 }
85 - if (!checkPortCallback.check(port)) {  
86 - return getPort(port, start, end, checkPortCallback); 106 + if (!checkPortCallback.check(current)) {
  107 + return getPort(current + 2, start, end, checkPortCallback);
87 } 108 }
88 - return port; 109 + return current;
89 } 110 }
90 } 111 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java
@@ -167,7 +167,7 @@ public class ZLMServerFactory { @@ -167,7 +167,7 @@ public class ZLMServerFactory {
167 // 默认为随机端口 167 // 默认为随机端口
168 int localPort = 0; 168 int localPort = 0;
169 if (userSetting.getGbSendStreamStrict()) { 169 if (userSetting.getGbSendStreamStrict()) {
170 - localPort = sendRtpPortManager.getNextPort(serverItem.getId()); 170 + localPort = sendRtpPortManager.getNextPort(serverItem);
171 if (localPort == 0) { 171 if (localPort == 0) {
172 return null; 172 return null;
173 } 173 }
@@ -203,7 +203,7 @@ public class ZLMServerFactory { @@ -203,7 +203,7 @@ public class ZLMServerFactory {
203 // 默认为随机端口 203 // 默认为随机端口
204 int localPort = 0; 204 int localPort = 0;
205 if (userSetting.getGbSendStreamStrict()) { 205 if (userSetting.getGbSendStreamStrict()) {
206 - localPort = sendRtpPortManager.getNextPort(serverItem.getId()); 206 + localPort = sendRtpPortManager.getNextPort(serverItem);
207 if (localPort == 0) { 207 if (localPort == 0) {
208 return null; 208 return null;
209 } 209 }
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaSendRtpPortInfo.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.media.zlm.dto;  
2 -  
3 -public class MediaSendRtpPortInfo {  
4 -  
5 - private int start;  
6 - private int end;  
7 - private String mediaServerId;  
8 -  
9 - private int current;  
10 -  
11 -  
12 - public MediaSendRtpPortInfo(int start, int end, String mediaServerId) {  
13 - this.start = start;  
14 - this.current = start;  
15 - this.end = end;  
16 - this.mediaServerId = mediaServerId;  
17 - }  
18 -  
19 - public int getStart() {  
20 - return start;  
21 - }  
22 -  
23 - public void setStart(int start) {  
24 - this.start = start;  
25 - }  
26 -  
27 - public int getEnd() {  
28 - return end;  
29 - }  
30 -  
31 - public void setEnd(int end) {  
32 - this.end = end;  
33 - }  
34 -  
35 - public String getMediaServerId() {  
36 - return mediaServerId;  
37 - }  
38 -  
39 - public void setMediaServerId(String mediaServerId) {  
40 - this.mediaServerId = mediaServerId;  
41 - }  
42 -  
43 - public int getCurrent() {  
44 - return current;  
45 - }  
46 -  
47 - public void setCurrent(int current) {  
48 - this.current = current;  
49 - }  
50 -}  
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -119,34 +119,6 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -119,34 +119,6 @@ public class MediaServerServiceImpl implements IMediaServerService {
119 if (ssrcFactory.hasMediaServerSSRC(mediaServerItem.getId())) { 119 if (ssrcFactory.hasMediaServerSSRC(mediaServerItem.getId())) {
120 ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null); 120 ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null);
121 } 121 }
122 - if (userSetting.getGbSendStreamStrict()) {  
123 - int startPort = 50000;  
124 - int endPort = 60000;  
125 - String sendRtpPortRange = mediaServerItem.getSendRtpPortRange();  
126 - if (sendRtpPortRange == null) {  
127 - logger.warn("[zlm] ] 未配置发流端口范围,默认使用50000到60000");  
128 - }else {  
129 - String[] sendRtpPortRangeArray = sendRtpPortRange.trim().split(",");  
130 - if (sendRtpPortRangeArray.length != 2) {  
131 - logger.warn("[zlm] ] 发流端口范围错误,默认使用50000到60000");  
132 - }else {  
133 - try {  
134 - startPort = Integer.parseInt(sendRtpPortRangeArray[0]);  
135 - endPort = Integer.parseInt(sendRtpPortRangeArray[1]);  
136 - if (endPort <= startPort) {  
137 - logger.warn("[zlm] ] 发流端口范围错误,结束端口应大于开始端口,使用默认端口");  
138 - startPort = 50000;  
139 - endPort = 60000;  
140 - }  
141 -  
142 - }catch (NumberFormatException e) {  
143 - logger.warn("[zlm] ] 发流端口范围错误,默认使用50000到60000");  
144 - }  
145 - }  
146 - }  
147 - logger.info("[[zlm] ] 配置发流端口范围,{}-{}", startPort, endPort);  
148 - sendRtpPortManager.initServerPort(mediaServerItem.getId(), startPort, endPort);  
149 - }  
150 // 查询redis是否存在此mediaServer 122 // 查询redis是否存在此mediaServer
151 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId(); 123 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();
152 Boolean hasKey = redisTemplate.hasKey(key); 124 Boolean hasKey = redisTemplate.hasKey(key);
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -269,7 +269,7 @@ public class PlayServiceImpl implements IPlayService { @@ -269,7 +269,7 @@ public class PlayServiceImpl implements IPlayService {
269 InviteErrorCode.SUCCESS.getCode(), 269 InviteErrorCode.SUCCESS.getCode(),
270 InviteErrorCode.SUCCESS.getMsg(), 270 InviteErrorCode.SUCCESS.getMsg(),
271 streamInfo); 271 streamInfo);
272 - logger.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(), 272 + logger.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(), channelId,
273 device.isSwitchPrimarySubStream() ? "辅码流" : "主码流"); 273 device.isSwitchPrimarySubStream() ? "辅码流" : "主码流");
274 snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channelId, ssrcInfo.getStream()); 274 snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channelId, ssrcInfo.getStream());
275 }, (event) -> { 275 }, (event) -> {
src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java
@@ -139,8 +139,8 @@ public class RtpController { @@ -139,8 +139,8 @@ public class RtpController {
139 redisTemplate.opsForValue().set(receiveKey, otherRtpSendInfo); 139 redisTemplate.opsForValue().set(receiveKey, otherRtpSendInfo);
140 if (isSend != null && isSend) { 140 if (isSend != null && isSend) {
141 // 预创建发流信息 141 // 预创建发流信息
142 - int portForVideo = sendRtpPortManager.getNextPort(mediaServerItem.getId());  
143 - int portForAudio = sendRtpPortManager.getNextPort(mediaServerItem.getId()); 142 + int portForVideo = sendRtpPortManager.getNextPort(mediaServerItem);
  143 + int portForAudio = sendRtpPortManager.getNextPort(mediaServerItem);
144 144
145 otherRtpSendInfo.setSendLocalIp(mediaServerItem.getSdpIp()); 145 otherRtpSendInfo.setSendLocalIp(mediaServerItem.getSdpIp());
146 otherRtpSendInfo.setSendLocalPortForVideo(portForVideo); 146 otherRtpSendInfo.setSendLocalPortForVideo(portForVideo);
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
@@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.conf.SipConfig; @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.conf.SipConfig;
8 import com.genersoft.iot.vmp.conf.UserSetting; 8 import com.genersoft.iot.vmp.conf.UserSetting;
9 import com.genersoft.iot.vmp.conf.VersionInfo; 9 import com.genersoft.iot.vmp.conf.VersionInfo;
10 import com.genersoft.iot.vmp.conf.exception.ControllerException; 10 import com.genersoft.iot.vmp.conf.exception.ControllerException;
  11 +import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
11 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 12 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
12 import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe; 13 import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
13 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 14 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
@@ -72,6 +73,9 @@ public class ServerController { @@ -72,6 +73,9 @@ public class ServerController {
72 @Autowired 73 @Autowired
73 private IRedisCatchStorage redisCatchStorage; 74 private IRedisCatchStorage redisCatchStorage;
74 75
  76 + @Autowired
  77 + private SendRtpPortManager sendRtpPortManager;
  78 +
75 79
76 @GetMapping(value = "/media_server/list") 80 @GetMapping(value = "/media_server/list")
77 @ResponseBody 81 @ResponseBody
@@ -262,4 +266,12 @@ public class ServerController { @@ -262,4 +266,12 @@ public class ServerController {
262 266
263 return result; 267 return result;
264 } 268 }
  269 +
  270 + @PostMapping(value = "/test/getPort")
  271 + @ResponseBody
  272 + public int getPort() {
  273 + int result = sendRtpPortManager.getNextPort(mediaServerService.getDefaultMediaServer());
  274 + System.out.println(result);
  275 + return result;
  276 + }
265 } 277 }