You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-25 05:23:13 +03:00
Support m.call.select_answer
Only send one if the answer has a party_id set Also change some event types to the enum and rename receivedAnswer to be more consistent
This commit is contained in:
@@ -46,6 +46,7 @@ export enum EventType {
|
|||||||
CallAnswer = "m.call.answer",
|
CallAnswer = "m.call.answer",
|
||||||
CallHangup = "m.call.hangup",
|
CallHangup = "m.call.hangup",
|
||||||
CallReject = "m.call.reject",
|
CallReject = "m.call.reject",
|
||||||
|
CallSelectAnswer = "m.call.select_answer",
|
||||||
KeyVerificationRequest = "m.key.verification.request",
|
KeyVerificationRequest = "m.key.verification.request",
|
||||||
KeyVerificationStart = "m.key.verification.start",
|
KeyVerificationStart = "m.key.verification.start",
|
||||||
KeyVerificationCancel = "m.key.verification.cancel",
|
KeyVerificationCancel = "m.key.verification.cancel",
|
||||||
|
|||||||
@@ -22,9 +22,10 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {logger} from '../logger';
|
import {logger} from '../logger';
|
||||||
import {EventEmitter} from "events";
|
import {EventEmitter} from 'events';
|
||||||
import * as utils from "../utils";
|
import * as utils from '../utils';
|
||||||
import MatrixEvent from "../models/event"
|
import MatrixEvent from '../models/event';
|
||||||
|
import {EventType} from '../@types/event';
|
||||||
|
|
||||||
// events: hangup, error(err), replaced(call), state(state, oldState)
|
// events: hangup, error(err), replaced(call), state(state, oldState)
|
||||||
|
|
||||||
@@ -208,6 +209,7 @@ export class MatrixCall extends EventEmitter {
|
|||||||
hangupParty: CallParty;
|
hangupParty: CallParty;
|
||||||
hangupReason: string;
|
hangupReason: string;
|
||||||
direction: CallDirection;
|
direction: CallDirection;
|
||||||
|
ourPartyId: string;
|
||||||
|
|
||||||
private client: any; // Fix when client is TSified
|
private client: any; // Fix when client is TSified
|
||||||
private forceTURN: boolean;
|
private forceTURN: boolean;
|
||||||
@@ -231,7 +233,6 @@ export class MatrixCall extends EventEmitter {
|
|||||||
private config: MediaStreamConstraints;
|
private config: MediaStreamConstraints;
|
||||||
private successor: MatrixCall;
|
private successor: MatrixCall;
|
||||||
private opponentVersion: number;
|
private opponentVersion: number;
|
||||||
private ourPartyId: string;
|
|
||||||
// The party ID of the other side: undefined if we haven't chosen a partner
|
// The party ID of the other side: undefined if we haven't chosen a partner
|
||||||
// yet, null if we have but they didn't send a party ID.
|
// yet, null if we have but they didn't send a party ID.
|
||||||
private opponentPartyId: string;
|
private opponentPartyId: string;
|
||||||
@@ -555,7 +556,7 @@ export class MatrixCall extends EventEmitter {
|
|||||||
// Continue to send no reason for user hangups temporarily, until
|
// Continue to send no reason for user hangups temporarily, until
|
||||||
// clients understand the user_hangup reason (voip v1)
|
// clients understand the user_hangup reason (voip v1)
|
||||||
if (reason !== CallErrorCode.UserHangup) content['reason'] = reason;
|
if (reason !== CallErrorCode.UserHangup) content['reason'] = reason;
|
||||||
this.sendVoipEvent('m.call.hangup', {});
|
this.sendVoipEvent(EventType.CallHangup, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -578,7 +579,7 @@ export class MatrixCall extends EventEmitter {
|
|||||||
|
|
||||||
logger.debug("Rejecting call: " + this.callId);
|
logger.debug("Rejecting call: " + this.callId);
|
||||||
this.terminate(CallParty.Local, CallErrorCode.UserHangup, true);
|
this.terminate(CallParty.Local, CallErrorCode.UserHangup, true);
|
||||||
this.sendVoipEvent('m.call.reject', {});
|
this.sendVoipEvent(EventType.CallReject, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -691,7 +692,7 @@ export class MatrixCall extends EventEmitter {
|
|||||||
|
|
||||||
private sendAnswer() {
|
private sendAnswer() {
|
||||||
this.setState(CallState.Connecting);
|
this.setState(CallState.Connecting);
|
||||||
this.sendVoipEvent('m.call.answer', this.answerContent).then(() => {
|
this.sendVoipEvent(EventType.CallAnswer, this.answerContent).then(() => {
|
||||||
// If this isn't the first time we've tried to send the answer,
|
// If this isn't the first time we've tried to send the answer,
|
||||||
// we may have candidates queued up, so send them now.
|
// we may have candidates queued up, so send them now.
|
||||||
this.sendCandidateQueue();
|
this.sendCandidateQueue();
|
||||||
@@ -842,24 +843,37 @@ export class MatrixCall extends EventEmitter {
|
|||||||
* Used by MatrixClient.
|
* Used by MatrixClient.
|
||||||
* @param {Object} msg
|
* @param {Object} msg
|
||||||
*/
|
*/
|
||||||
async receivedAnswer(msg: MatrixEvent) {
|
async onAnswerReceived(event: MatrixEvent) {
|
||||||
if (this.state === CallState.Ended) {
|
if (this.state === CallState.Ended) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.opponentPartyId !== undefined) {
|
if (this.opponentPartyId !== undefined) {
|
||||||
logger.info(
|
logger.info(
|
||||||
`Ignoring answer from party ID ${msg.party_id}: ` +
|
`Ignoring answer from party ID ${event.getContent().party_id}: ` +
|
||||||
`we already have an answer/reject from ${this.opponentPartyId}`,
|
`we already have an answer/reject from ${this.opponentPartyId}`,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.opponentVersion = msg.version;
|
this.opponentVersion = event.getContent().version;
|
||||||
this.opponentPartyId = msg.party_id || null;
|
this.opponentPartyId = event.getContent().party_id || null;
|
||||||
|
|
||||||
|
// If the answer we selected has a party_id, send a select_answer event
|
||||||
|
if (this.opponentPartyId !== null) {
|
||||||
|
try {
|
||||||
|
await this.sendVoipEvent(EventType.CallSelectAnswer, {
|
||||||
|
selected_party_id: this.opponentPartyId,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
// This isn't fatal, and will just mean that if another party has raced to answer
|
||||||
|
// the call, they won't know they got rejected, so we carry on & don't retry.
|
||||||
|
logger.warn("Failed to send select_answer event", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.peerConn.setRemoteDescription(msg.answer);
|
await this.peerConn.setRemoteDescription(event.getContent().answer);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.debug("Failed to set remote description", e);
|
logger.debug("Failed to set remote description", e);
|
||||||
this.terminate(CallParty.Local, CallErrorCode.SetRemoteDescription, false);
|
this.terminate(CallParty.Local, CallErrorCode.SetRemoteDescription, false);
|
||||||
@@ -869,6 +883,26 @@ export class MatrixCall extends EventEmitter {
|
|||||||
this.setState(CallState.Connecting);
|
this.setState(CallState.Connecting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onSelectAnswerReceived(event: MatrixEvent) {
|
||||||
|
if (this.direction !== CallDirection.Inbound) {
|
||||||
|
logger.warn("Got select_answer for an outbound call: ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedPartyId = event.getContent().selected_party_id;
|
||||||
|
|
||||||
|
if (selectedPartyId === undefined || selectedPartyId === null) {
|
||||||
|
logger.warn("Got nonsensical select_answer with null/undefined selected_party_id: ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedPartyId !== this.ourPartyId) {
|
||||||
|
logger.info(`Got select_answer for party ID ${selectedPartyId}: we are party ID ${this.ourPartyId}.`);
|
||||||
|
// The other party has picked somebody else's answer
|
||||||
|
this.terminate(CallParty.Remote, CallErrorCode.AnsweredElsewhere, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private gotLocalOffer = async (description: RTCSessionDescriptionInit) => {
|
private gotLocalOffer = async (description: RTCSessionDescriptionInit) => {
|
||||||
logger.debug("Created offer: ", description);
|
logger.debug("Created offer: ", description);
|
||||||
|
|
||||||
@@ -905,7 +939,7 @@ export class MatrixCall extends EventEmitter {
|
|||||||
lifetime: CALL_TIMEOUT_MS,
|
lifetime: CALL_TIMEOUT_MS,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
await this.sendVoipEvent('m.call.invite', content);
|
await this.sendVoipEvent(EventType.CallInvite, content);
|
||||||
this.setState(CallState.InviteSent);
|
this.setState(CallState.InviteSent);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.state === CallState.InviteSent) {
|
if (this.state === CallState.InviteSent) {
|
||||||
@@ -1212,7 +1246,7 @@ export class MatrixCall extends EventEmitter {
|
|||||||
candidates: cands,
|
candidates: cands,
|
||||||
};
|
};
|
||||||
logger.debug("Attempting to send " + cands.length + " candidates");
|
logger.debug("Attempting to send " + cands.length + " candidates");
|
||||||
this.sendVoipEvent('m.call.candidates', content).then(() => {
|
this.sendVoipEvent(EventType.CallCandidates, content).then(() => {
|
||||||
this.candidateSendTries = 0;
|
this.candidateSendTries = 0;
|
||||||
this.sendCandidateQueue();
|
this.sendCandidateQueue();
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ export class CallEventHandler {
|
|||||||
call.onAnsweredElsewhere(content);
|
call.onAnsweredElsewhere(content);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
call.receivedAnswer(content);
|
call.onAnswerReceived(event);
|
||||||
}
|
}
|
||||||
} else if (event.getType() === EventType.CallCandidates) {
|
} else if (event.getType() === EventType.CallCandidates) {
|
||||||
if (event.getSender() === this.client.credentials.userId) {
|
if (event.getSender() === this.client.credentials.userId) {
|
||||||
@@ -251,6 +251,13 @@ export class CallEventHandler {
|
|||||||
this.calls.delete(content.call_id);
|
this.calls.delete(content.call_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (event.getType() === EventType.CallSelectAnswer) {
|
||||||
|
if (event.getContent().party_id === call.ourPartyId) {
|
||||||
|
// Ignore remote echo
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
call.onSelectAnswerReceived(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user