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 3 import com.genersoft.iot.vmp.common.VideoManagerConstants;
4 4 import com.genersoft.iot.vmp.conf.UserSetting;
5 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 7 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  8 +import org.apache.commons.lang3.math.NumberUtils;
8 9 import org.slf4j.Logger;
9 10 import org.slf4j.LoggerFactory;
10 11 import org.springframework.beans.factory.annotation.Autowired;
11 12 import org.springframework.data.redis.core.RedisTemplate;
  13 +import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
12 14 import org.springframework.stereotype.Component;
13 15  
14 16 import java.util.HashMap;
... ... @@ -26,23 +28,14 @@ public class SendRtpPortManager {
26 28 @Autowired
27 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 39 String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX
47 40 + userSetting.getServerId() + "_*";
48 41 List<Object> queryResult = RedisUtil.scan(redisTemplate, key);
... ... @@ -54,14 +47,39 @@ public class SendRtpPortManager {
54 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 85 interface CheckPortCallback{
... ... @@ -69,22 +87,25 @@ public class SendRtpPortManager {
69 87 }
70 88  
71 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 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 167 // 默认为随机端口
168 168 int localPort = 0;
169 169 if (userSetting.getGbSendStreamStrict()) {
170   - localPort = sendRtpPortManager.getNextPort(serverItem.getId());
  170 + localPort = sendRtpPortManager.getNextPort(serverItem);
171 171 if (localPort == 0) {
172 172 return null;
173 173 }
... ... @@ -203,7 +203,7 @@ public class ZLMServerFactory {
203 203 // 默认为随机端口
204 204 int localPort = 0;
205 205 if (userSetting.getGbSendStreamStrict()) {
206   - localPort = sendRtpPortManager.getNextPort(serverItem.getId());
  206 + localPort = sendRtpPortManager.getNextPort(serverItem);
207 207 if (localPort == 0) {
208 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 119 if (ssrcFactory.hasMediaServerSSRC(mediaServerItem.getId())) {
120 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 122 // 查询redis是否存在此mediaServer
151 123 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();
152 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 269 InviteErrorCode.SUCCESS.getCode(),
270 270 InviteErrorCode.SUCCESS.getMsg(),
271 271 streamInfo);
272   - logger.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(),
  272 + logger.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(), channelId,
273 273 device.isSwitchPrimarySubStream() ? "辅码流" : "主码流");
274 274 snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channelId, ssrcInfo.getStream());
275 275 }, (event) -> {
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java
... ... @@ -139,8 +139,8 @@ public class RtpController {
139 139 redisTemplate.opsForValue().set(receiveKey, otherRtpSendInfo);
140 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 145 otherRtpSendInfo.setSendLocalIp(mediaServerItem.getSdpIp());
146 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 8 import com.genersoft.iot.vmp.conf.UserSetting;
9 9 import com.genersoft.iot.vmp.conf.VersionInfo;
10 10 import com.genersoft.iot.vmp.conf.exception.ControllerException;
  11 +import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
11 12 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
12 13 import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
13 14 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
... ... @@ -72,6 +73,9 @@ public class ServerController {
72 73 @Autowired
73 74 private IRedisCatchStorage redisCatchStorage;
74 75  
  76 + @Autowired
  77 + private SendRtpPortManager sendRtpPortManager;
  78 +
75 79  
76 80 @GetMapping(value = "/media_server/list")
77 81 @ResponseBody
... ... @@ -262,4 +266,12 @@ public class ServerController {
262 266  
263 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 }
... ...