package im.rosetta.calls; import java.util.HashMap; import io.g365sfu.Room; import io.orprotocol.ProtocolException; import io.orprotocol.client.Client; import io.orprotocol.packet.Packet; public class CallSession { public String callId; public String joinToken; public Long createdAt; public Long ringingTimeout; /** * Клиенты которым сейчас идет дозвон (публичные ключи) * Клиенты в этом списке не могут принимать другие звонки, так как они уже заняты дозвоном, * но они еще не в звонке, так как не приняли звонок * * Клиенты удаляются из этого списка, когда они принимают звонок или отклоняют его, тогда они либо переходят в звонок, либо становятся свободными для других звонков */ public HashMap ringing; /** * Клиенты, которые уже приняли звонок и находятся в звонке (публичные ключи) и их сокеты * pk -> client */ public HashMap clients; /** * Если звонок активен у него появляется комната, иначе комната null */ public Room room; public CallSession(String callId, String joinToken, Long ringingTimeout) { this.callId = callId; this.joinToken = joinToken; this.clients = new HashMap<>(); this.ringing = new HashMap<>(); this.createdAt = System.currentTimeMillis(); this.ringingTimeout = ringingTimeout; } public void joinCall(String publicKey, Client client) { if(this.ringing.containsKey(publicKey)) { this.ringing.remove(publicKey); } this.clients.put(publicKey, client); } /** * Получаем публичный ключ клиента по его сокету, чтобы понимать, кто отправляет сигналы в рамках звонка * @param client Сокет клиента, для которого нужно получить публичный ключ * @return Публичный ключ клиента, или null если клиент не найден в сессии звонка */ public String getPublicKey(Client client) { for (String publicKey : this.clients.keySet()) { if (this.clients.get(publicKey).equals(client)) { return publicKey; } } return null; } public String getCallId() { return this.callId; } public String getJoinToken() { return this.joinToken; } public void addRinging(String publicKey) { this.ringing.put(publicKey, System.currentTimeMillis()); } public void setRoom(Room room) { this.room = room; } public Room getRoom() { return this.room; } /** * Отправляем пакет всем участникам звонка, кроме исключенного клиента (обычно отправителя) * @param packet Пакет для отправки * @param excludeClient Клиент, которому не нужно отправлять пакет (обычно отправитель) * @throws ProtocolException Если произошла ошибка при отправке пакета клиенту */ public void sendPacket(Packet packet, Client excludeClient) throws ProtocolException { for (Client client : this.clients.values()) { if (!client.equals(excludeClient)) { client.send(packet); } } } /** * Проверяем, нужно ли удалять сессию звонка. * Сессию звонка нужно удалять, если в ней меньше 2 клиентов и при этом нет клиентов в состоянии дозвона, * или если сессия была создана более 1 минуты назад, так как это значит, что клиенты не ответили на звонок и он устарел * @return true, если сессию звонка нужно удалять, false иначе */ public boolean shouldRemove() { return this.clients.size() <= 1 && (this.ringing.size() == 0 || System.currentTimeMillis() - this.createdAt > this.ringingTimeout); } }