package com.genersoft.iot.vmp.media.zlm; 
 | 
  
 | 
import com.genersoft.iot.vmp.common.VideoManagerConstants; 
 | 
import com.genersoft.iot.vmp.conf.UserSetting; 
 | 
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; 
 | 
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 
 | 
import com.genersoft.iot.vmp.utils.redis.RedisUtil; 
 | 
import org.apache.commons.lang3.math.NumberUtils; 
 | 
import org.slf4j.Logger; 
 | 
import org.slf4j.LoggerFactory; 
 | 
import org.springframework.beans.factory.annotation.Autowired; 
 | 
import org.springframework.data.redis.core.RedisTemplate; 
 | 
import org.springframework.data.redis.support.atomic.RedisAtomicInteger; 
 | 
import org.springframework.stereotype.Component; 
 | 
  
 | 
import java.util.HashMap; 
 | 
import java.util.List; 
 | 
import java.util.Map; 
 | 
  
 | 
@Component 
 | 
public class SendRtpPortManager { 
 | 
  
 | 
    private final static Logger logger = LoggerFactory.getLogger(SendRtpPortManager.class); 
 | 
  
 | 
    @Autowired 
 | 
    private UserSetting userSetting; 
 | 
  
 | 
    @Autowired 
 | 
    private RedisTemplate<Object, Object> redisTemplate; 
 | 
  
 | 
    private final String KEY = "VM_MEDIA_SEND_RTP_PORT_"; 
 | 
  
 | 
    public synchronized int getNextPort(MediaServerItem mediaServer) { 
 | 
        if (mediaServer == null) { 
 | 
            logger.warn("[发送端口管理] 参数错误,mediaServer为NULL"); 
 | 
            return -1; 
 | 
        } 
 | 
        String sendIndexKey = KEY + userSetting.getServerId() + "_" +  mediaServer.getId(); 
 | 
        String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX 
 | 
                + userSetting.getServerId() + "_*"; 
 | 
        List<Object> queryResult = RedisUtil.scan(redisTemplate, key); 
 | 
        Map<Integer, SendRtpItem> sendRtpItemMap = new HashMap<>(); 
 | 
  
 | 
        for (Object o : queryResult) { 
 | 
            SendRtpItem sendRtpItem = (SendRtpItem) redisTemplate.opsForValue().get(o); 
 | 
            if (sendRtpItem != null) { 
 | 
                sendRtpItemMap.put(sendRtpItem.getLocalPort(), sendRtpItem); 
 | 
            } 
 | 
        } 
 | 
        String sendRtpPortRange = mediaServer.getSendRtpPortRange(); 
 | 
        int startPort; 
 | 
        int endPort; 
 | 
        if (sendRtpPortRange != null) { 
 | 
            String[] portArray = sendRtpPortRange.split(","); 
 | 
            if (portArray.length != 2 || !NumberUtils.isParsable(portArray[0]) || !NumberUtils.isParsable(portArray[1])) { 
 | 
                logger.warn("{}发送端口配置格式错误,自动使用50000-60000作为端口范围", mediaServer.getId()); 
 | 
                startPort = 50000; 
 | 
                endPort = 60000; 
 | 
            }else { 
 | 
                if ( Integer.parseInt(portArray[1]) - Integer.parseInt(portArray[0]) < 1) { 
 | 
                    logger.warn("{}发送端口配置错误,结束端口至少比开始端口大一,自动使用50000-60000作为端口范围", mediaServer.getId()); 
 | 
                    startPort = 50000; 
 | 
                    endPort = 60000; 
 | 
                }else { 
 | 
                    startPort = Integer.parseInt(portArray[0]); 
 | 
                    endPort = Integer.parseInt(portArray[1]); 
 | 
                } 
 | 
            } 
 | 
        }else { 
 | 
            logger.warn("{}未设置发送端口默认值,自动使用50000-60000作为端口范围", mediaServer.getId()); 
 | 
            startPort = 50000; 
 | 
            endPort = 60000; 
 | 
        } 
 | 
        if (redisTemplate == null || redisTemplate.getConnectionFactory() == null) { 
 | 
            logger.warn("{}获取redis连接信息失败", mediaServer.getId()); 
 | 
            return -1; 
 | 
        } 
 | 
//        RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(sendIndexKey , redisTemplate.getConnectionFactory()); 
 | 
//        return redisAtomicInteger.getAndUpdate((current)->{ 
 | 
//            return getPort(current, startPort, endPort, checkPort-> !sendRtpItemMap.containsKey(checkPort)); 
 | 
//        }); 
 | 
        return getSendPort(startPort, endPort, sendIndexKey, sendRtpItemMap); 
 | 
    } 
 | 
  
 | 
    private synchronized int getSendPort(int startPort, int endPort, String sendIndexKey, Map<Integer, SendRtpItem> sendRtpItemMap){ 
 | 
        RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(sendIndexKey , redisTemplate.getConnectionFactory()); 
 | 
        if (redisAtomicInteger.get() < startPort) { 
 | 
            redisAtomicInteger.set(startPort); 
 | 
            return startPort; 
 | 
        }else { 
 | 
            int port = redisAtomicInteger.getAndIncrement(); 
 | 
            if (port > endPort) { 
 | 
                redisAtomicInteger.set(startPort); 
 | 
                if (sendRtpItemMap.containsKey(startPort)) { 
 | 
                    return getSendPort(startPort, endPort, sendIndexKey, sendRtpItemMap); 
 | 
                }else { 
 | 
                    return startPort; 
 | 
                } 
 | 
            } 
 | 
            if (sendRtpItemMap.containsKey(port)) { 
 | 
                return getSendPort(startPort, endPort, sendIndexKey, sendRtpItemMap); 
 | 
            }else { 
 | 
                return port; 
 | 
            } 
 | 
        } 
 | 
  
 | 
    } 
 | 
  
 | 
    interface CheckPortCallback{ 
 | 
        boolean check(int port); 
 | 
    } 
 | 
  
 | 
    private int getPort(int current, int start, int end, CheckPortCallback checkPortCallback) { 
 | 
        if (current <= 0) { 
 | 
            if (start%2 == 0) { 
 | 
                current = start; 
 | 
            }else { 
 | 
                current = start + 1; 
 | 
            } 
 | 
        }else { 
 | 
            current += 2; 
 | 
            if (current > end) { 
 | 
                if (start%2 == 0) { 
 | 
                    current = start; 
 | 
                }else { 
 | 
                    current = start + 1; 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
        if (!checkPortCallback.check(current)) { 
 | 
            return getPort(current + 2, start, end, checkPortCallback); 
 | 
        } 
 | 
        return current; 
 | 
    } 
 | 
} 
 |