120 lines
4.5 KiB
Java
120 lines
4.5 KiB
Java
package im.rosetta.calls;
|
||
|
||
import java.util.ArrayList;
|
||
import java.util.List;
|
||
import java.util.concurrent.Executors;
|
||
import java.util.concurrent.ScheduledExecutorService;
|
||
import java.util.concurrent.TimeUnit;
|
||
|
||
import im.rosetta.client.ClientManager;
|
||
import im.rosetta.packet.Packet26SignalPeer;
|
||
import im.rosetta.packet.runtime.NetworkSignalType;
|
||
import io.g365sfu.Room;
|
||
import io.orprotocol.ProtocolException;
|
||
import io.orprotocol.client.Client;
|
||
import io.orprotocol.packet.Packet;
|
||
|
||
public class CallManager {
|
||
|
||
private List<CallSession> callSessions = new ArrayList<>();
|
||
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
||
private static final long RINGING_TIMEOUT = 30 * 1000;
|
||
private ClientManager clientManager;
|
||
|
||
|
||
public CallManager(ClientManager clientManager) {
|
||
this.clientManager = clientManager;
|
||
scheduler.scheduleAtFixedRate(this::cleanupCallSessions, 0, 1, TimeUnit.SECONDS);
|
||
}
|
||
|
||
public void cleanupCallSessions() {
|
||
/**
|
||
* Такая конструкция нужна для избежания ConcurrentModificationException,
|
||
* так как мы не можем удалять элементы из списка, по которому проходим в цикле,
|
||
* поэтому мы сначала собираем сессии звонков, которые нужно удалить, а потом
|
||
* удаляем их из основного списка
|
||
*/
|
||
List<CallSession> sessionsToRemove = new ArrayList<>();
|
||
for (CallSession session : this.callSessions) {
|
||
if (session.shouldRemove()) {
|
||
/**
|
||
* Отправляем всем в сессии что звонок завершился, так как он устарел, и удаляем сессию из списка активных сессий
|
||
*/
|
||
Packet26SignalPeer rtout = new Packet26SignalPeer();
|
||
rtout.setSignalType(NetworkSignalType.RINGING_TIMEOUT);
|
||
Packet26SignalPeer endCallPacket = new Packet26SignalPeer();
|
||
endCallPacket.setSignalType(NetworkSignalType.END_CALL);
|
||
endCallPacket.setJoinToken(session.getJoinToken());
|
||
endCallPacket.setCallId(session.getCallId());
|
||
|
||
try {
|
||
session.sendPacket(rtout, null);
|
||
this.sendPacketToRinging(session, endCallPacket);
|
||
} catch (ProtocolException e) {
|
||
e.printStackTrace();
|
||
}
|
||
sessionsToRemove.add(session);
|
||
}
|
||
}
|
||
for (CallSession session : sessionsToRemove) {
|
||
this.callSessions.remove(session);
|
||
}
|
||
}
|
||
|
||
public CallSession createCall(String callId, String joinToken) {
|
||
CallSession session = new CallSession(callId, joinToken, RINGING_TIMEOUT);
|
||
this.callSessions.add(session);
|
||
return session;
|
||
}
|
||
|
||
public CallSession getCallSession(String callId, String joinToken) {
|
||
for (CallSession session : this.callSessions) {
|
||
if (session.getCallId().equals(callId) && session.getJoinToken().equals(joinToken)) {
|
||
return session;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public CallSession getCallSession(Room room) {
|
||
for (CallSession session : this.callSessions) {
|
||
if (session.getRoom() != null && session.getRoom().equals(room)) {
|
||
return session;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public boolean isBusy(String publicKey) {
|
||
for (CallSession session : this.callSessions) {
|
||
if (session.clients.containsKey(publicKey)) {
|
||
return true;
|
||
}
|
||
if(session.ringing.containsKey(publicKey)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
public void sendPacketToRinging(CallSession session, Packet packet) throws ProtocolException {
|
||
for (String publicKey : session.ringing.keySet()) {
|
||
this.clientManager.sendPacketToAuthorizedPK(publicKey, packet);
|
||
}
|
||
}
|
||
|
||
public CallSession getCallSession(Client client) {
|
||
for (CallSession session : this.callSessions) {
|
||
if (session.clients.containsValue(client)) {
|
||
return session;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public void removeSession(CallSession session) {
|
||
this.callSessions.remove(session);
|
||
}
|
||
|
||
}
|