Звонки: выбор одной callee-сессии и авто-закрытие входящего на других устройствах

This commit is contained in:
AidarKC 2026-05-01 19:26:32 +03:00
parent db93eace30
commit e73328461e
3 changed files with 81 additions and 3 deletions

View File

@ -1,2 +1,2 @@
client.version=1.2.32
server.version=1.2.26
client.version=1.2.33
server.version=1.2.27

View File

@ -1366,7 +1366,51 @@ export async function handleIncomingCallSignal(evt) {
const call = getCall(callId);
if (!call) return;
if (!call.remoteSessionId) call.remoteSessionId = fromSessionId;
if (call.direction === 'out') {
if (type === TYPES.RINGING) {
if (!call.remoteSessionId && fromSessionId) {
call.remoteSessionId = fromSessionId;
}
if (call.remoteSessionId && fromSessionId && call.remoteSessionId !== fromSessionId) {
await emitDebug(
call,
'info',
'ringing_from_non_selected_session_ignored',
`selected=${call.remoteSessionId}; from=${fromSessionId}`,
);
return;
}
} else if (type === TYPES.ACCEPT) {
if (fromSessionId) {
if (!call.remoteSessionId || !call.initialOfferSent) {
call.remoteSessionId = fromSessionId;
} else if (call.remoteSessionId !== fromSessionId) {
await emitDebug(
call,
'warn',
'accept_from_non_selected_session_ignored',
`selected=${call.remoteSessionId}; from=${fromSessionId}`,
);
return;
}
}
} else {
if (call.remoteSessionId && fromSessionId && call.remoteSessionId !== fromSessionId) {
await emitDebug(
call,
'info',
'signal_from_non_selected_session_ignored',
`type=${type}; selected=${call.remoteSessionId}; from=${fromSessionId}`,
);
return;
}
if (!call.remoteSessionId && fromSessionId) {
call.remoteSessionId = fromSessionId;
}
}
} else if (!call.remoteSessionId) {
call.remoteSessionId = fromSessionId;
}
if (type === TYPES.RINGING) {
if (call.direction === 'out' && call.phase === 'searching') {

View File

@ -20,6 +20,8 @@ import java.util.Set;
public class Net_CallSignalToSession_Handler implements JsonMessageHandler {
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final int TYPE_ACCEPT = 120;
private static final int TYPE_HANGUP = 150;
@Override
public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) throws Exception {
@ -69,6 +71,10 @@ public class Net_CallSignalToSession_Handler implements JsonMessageHandler {
boolean delivered = WsEventSender.sendEvent(targetCtx, "IncomingCallSignal", eventId, payload);
if (type == TYPE_ACCEPT) {
notifyAcceptedOnOtherSessions(ctx, callId);
}
Net_CallSignalToSession_Response resp = new Net_CallSignalToSession_Response();
resp.setOp(req.getOp());
resp.setRequestId(req.getRequestId());
@ -76,4 +82,32 @@ public class Net_CallSignalToSession_Handler implements JsonMessageHandler {
resp.setDelivered(delivered);
return resp;
}
private void notifyAcceptedOnOtherSessions(ConnectionContext accepterCtx, String callId) {
if (accepterCtx == null) return;
String login = accepterCtx.getLogin();
String acceptedSessionId = accepterCtx.getSessionId();
if (login == null || login.isBlank() || acceptedSessionId == null || acceptedSessionId.isBlank() || callId == null || callId.isBlank()) {
return;
}
Set<ConnectionContext> sameUserSessions = ActiveConnectionsRegistry.getInstance().getByLogin(login);
for (ConnectionContext siblingCtx : sameUserSessions) {
if (siblingCtx == null || siblingCtx.getWsSession() == null || !siblingCtx.getWsSession().isOpen()) continue;
if (acceptedSessionId.equals(siblingCtx.getSessionId())) continue;
String siblingEventId = NetIdGenerator.eventId("evt");
ObjectNode siblingPayload = MAPPER.createObjectNode();
siblingPayload.put("eventId", siblingEventId);
siblingPayload.put("fromLogin", login);
siblingPayload.put("fromSessionId", acceptedSessionId);
siblingPayload.put("toLogin", login);
siblingPayload.put("callId", callId);
siblingPayload.put("type", TYPE_HANGUP);
siblingPayload.put("data", "accepted_on_other_device");
siblingPayload.put("timeMs", System.currentTimeMillis());
WsEventSender.sendEvent(siblingCtx, "IncomingCallSignal", siblingEventId, siblingPayload);
}
}
}