package org.bigbluebutton.voiceconf.sip; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.red5.app.sip.codecs.Codec; import org.red5.logging.Red5LoggerFactory; import org.slf4j.Logger; public class GlobalCall { private static final Logger log = Red5LoggerFactory.getLogger( GlobalCall.class, "sip" ); // Configure hashmap properly (ralam sept 1, 2015) // https://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-misuse/ // private static Map<String,String> roomToStreamMap = new ConcurrentHashMap<String, String>(8, 0.9f, 1); private static Map<String,Codec> roomToCodecMap = new ConcurrentHashMap<String, Codec>(8, 0.9f, 1); private static Map<String,KeepGlobalAudioAlive> globalAudioKeepAliverMap = new ConcurrentHashMap<String, KeepGlobalAudioAlive>(8, 0.9f, 1); private static Map<String, VoiceConfToListenOnlyUsersMap> voiceConfToListenOnlyUsersMap = new ConcurrentHashMap<String, VoiceConfToListenOnlyUsersMap>(8, 0.9f, 1); public static synchronized boolean reservePlaceToCreateGlobal(String roomName) { if (roomToStreamMap.containsKey(roomName)) { log.debug("There's already a global audio stream for room {}, no need to create a new one", roomName); return false; } else { log.debug("Reserving the place to create a global audio stream for room {}", roomName); roomToStreamMap.put(roomName, "reserved"); return true; } } public static synchronized void addGlobalAudioStream(String voiceConf, String globalAudioStreamName, Codec sipCodec, SipConnectInfo connInfo) { log.debug("Adding a global audio stream to room {}", voiceConf); roomToStreamMap.put(voiceConf, globalAudioStreamName); roomToCodecMap.put(voiceConf, sipCodec); voiceConfToListenOnlyUsersMap.put(voiceConf, new VoiceConfToListenOnlyUsersMap(voiceConf)); KeepGlobalAudioAlive globalAudioKeepAlive = new KeepGlobalAudioAlive(connInfo.getSocket(), connInfo, sipCodec.getCodecId()); globalAudioKeepAliverMap.put(voiceConf, globalAudioKeepAlive); globalAudioKeepAlive.start(); } public static synchronized String getGlobalAudioStream(String voiceConf) { return roomToStreamMap.get(voiceConf); } public static synchronized boolean removeRoomIfUnused(String voiceConf) { if (voiceConfToListenOnlyUsersMap.containsKey(voiceConf) && voiceConfToListenOnlyUsersMap.get(voiceConf).numUsers() <= 0) { removeRoom(voiceConf); return true; } else { return false; } } private static void removeRoom(String voiceConf) { log.debug("Removing global audio stream of room {}", voiceConf); roomToStreamMap.remove(voiceConf); voiceConfToListenOnlyUsersMap.remove(voiceConf); roomToCodecMap.remove(voiceConf); KeepGlobalAudioAlive globalAudioKeepAlive = globalAudioKeepAliverMap.get(voiceConf); globalAudioKeepAlive.halt(); globalAudioKeepAliverMap.remove(voiceConf); } public static synchronized void addUser(String clientId, String callerIdName, String voiceConf) { if (voiceConfToListenOnlyUsersMap.containsKey(voiceConf)) { VoiceConfToListenOnlyUsersMap map = voiceConfToListenOnlyUsersMap.get(voiceConf); map.addUser(clientId, callerIdName); int numUsers = map.numUsers(); log.debug("Adding new user to voiceConf [{}], current number of users on global stream is {}", voiceConf, numUsers); } } public static synchronized ListenOnlyUser removeUser(String clientId, String voiceConf) { if (voiceConfToListenOnlyUsersMap.containsKey(voiceConf)) { return voiceConfToListenOnlyUsersMap.get(voiceConf).removeUser(clientId); } return null; } public static Codec getRoomCodec(String roomName) { return roomToCodecMap.get(roomName); } }