1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-25 05:23:13 +03:00

Merge pull request #1559 from matrix-org/dbkr/ignore_party_id_v0

Ignore party ID if opponent is v0
This commit is contained in:
David Baker
2020-12-21 13:47:33 +00:00
committed by GitHub
5 changed files with 78 additions and 8 deletions

View File

@@ -142,7 +142,7 @@ describe('Call', function() {
await call.onAnswerReceived({ await call.onAnswerReceived({
getContent: () => { getContent: () => {
return { return {
version: 0, version: 1,
call_id: call.callId, call_id: call.callId,
party_id: 'the_correct_party_id', party_id: 'the_correct_party_id',
answer: { answer: {
@@ -156,7 +156,7 @@ describe('Call', function() {
call.onRemoteIceCandidatesReceived({ call.onRemoteIceCandidatesReceived({
getContent: () => { getContent: () => {
return { return {
version: 0, version: 1,
call_id: call.callId, call_id: call.callId,
party_id: 'the_correct_party_id', party_id: 'the_correct_party_id',
candidates: [ candidates: [
@@ -173,7 +173,7 @@ describe('Call', function() {
call.onRemoteIceCandidatesReceived({ call.onRemoteIceCandidatesReceived({
getContent: () => { getContent: () => {
return { return {
version: 0, version: 1,
call_id: call.callId, call_id: call.callId,
party_id: 'some_other_party_id', party_id: 'some_other_party_id',
candidates: [ candidates: [

View File

@@ -48,6 +48,7 @@ export enum EventType {
CallReject = "m.call.reject", CallReject = "m.call.reject",
CallSelectAnswer = "m.call.select_answer", CallSelectAnswer = "m.call.select_answer",
CallNegotiate = "m.call.negotiate", CallNegotiate = "m.call.negotiate",
CallReplaces = "m.call.replaces",
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",

View File

@@ -180,6 +180,9 @@ function keyFromRecoverySession(session, decryptionKey) {
* @param {boolean} [opts.forceTURN] * @param {boolean} [opts.forceTURN]
* Optional. Whether relaying calls through a TURN server should be forced. * Optional. Whether relaying calls through a TURN server should be forced.
* *
* @param {boolean} [opts.supportsTransfer]
* Optional. True to advertise support for call transfers to other parties on Matrix calls.
*
* @param {boolean} [opts.fallbackICEServerAllowed] * @param {boolean} [opts.fallbackICEServerAllowed]
* Optional. Whether to allow a fallback ICE server should be used for negotiating a * Optional. Whether to allow a fallback ICE server should be used for negotiating a
* WebRTC connection if the homeserver doesn't provide any servers. Defaults to false. * WebRTC connection if the homeserver doesn't provide any servers. Defaults to false.
@@ -364,6 +367,7 @@ export function MatrixClient(opts) {
this._cryptoCallbacks = opts.cryptoCallbacks || {}; this._cryptoCallbacks = opts.cryptoCallbacks || {};
this._forceTURN = opts.forceTURN || false; this._forceTURN = opts.forceTURN || false;
this._supportsTransfer = opts.supportsTransfer || false;
this._fallbackICEServerAllowed = opts.fallbackICEServerAllowed || false; this._fallbackICEServerAllowed = opts.fallbackICEServerAllowed || false;
// List of which rooms have encryption enabled: separate from crypto because // List of which rooms have encryption enabled: separate from crypto because
@@ -696,6 +700,14 @@ MatrixClient.prototype.setForceTURN = function(forceTURN) {
this._forceTURN = forceTURN; this._forceTURN = forceTURN;
}; };
/**
* Set whether to advertise trabsfer support to other parties on Matrix calls.
* @param {bool} supportsTransfer True to advertise the 'm.call.transeree' capability
*/
MatrixClient.prototype.setSupportsTransfer = function(supportsTransfer) {
this._supportsTransfer = supportsTransfer;
};
/** /**
* Get the current sync state. * Get the current sync state.
* @return {?string} the sync state, which may be null. * @return {?string} the sync state, which may be null.

View File

@@ -142,6 +142,7 @@ export interface ICreateClientOpts {
unstableClientRelationAggregation?: boolean; unstableClientRelationAggregation?: boolean;
verificationMethods?: Array<any>; verificationMethods?: Array<any>;
forceTURN?: boolean; forceTURN?: boolean;
supportsTransfer?: boolean,
fallbackICEServerAllowed?: boolean; fallbackICEServerAllowed?: boolean;
cryptoCallbacks?: ICryptoCallbacks; cryptoCallbacks?: ICryptoCallbacks;
} }

View File

@@ -27,6 +27,7 @@ import * as utils from '../utils';
import MatrixEvent from '../models/event'; import MatrixEvent from '../models/event';
import {EventType} from '../@types/event'; import {EventType} from '../@types/event';
import { RoomMember } from '../models/room-member'; import { RoomMember } from '../models/room-member';
import { randomString } from '../randomstring';
// events: hangup, error(err), replaced(call), state(state, oldState) // events: hangup, error(err), replaced(call), state(state, oldState)
@@ -60,6 +61,10 @@ interface TurnServer {
ttl?: number, ttl?: number,
} }
interface CallCapabilities {
'm.call.transferee': boolean,
}
export enum CallState { export enum CallState {
Fledgling = 'fledgling', Fledgling = 'fledgling',
InviteSent = 'invite_sent', InviteSent = 'invite_sent',
@@ -194,6 +199,10 @@ export class CallError extends Error {
} }
} }
function genCallID() {
return Date.now() + randomString(16);
}
/** /**
* Construct a new Matrix Call. * Construct a new Matrix Call.
* @constructor * @constructor
@@ -240,6 +249,7 @@ export class MatrixCall extends EventEmitter {
// 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;
private opponentCaps: CallCapabilities;
private inviteTimeout: NodeJS.Timeout; // in the browser it's 'number' private inviteTimeout: NodeJS.Timeout; // in the browser it's 'number'
// The logic of when & if a call is on hold is nontrivial and explained in is*OnHold // The logic of when & if a call is on hold is nontrivial and explained in is*OnHold
@@ -275,7 +285,7 @@ export class MatrixCall extends EventEmitter {
utils.checkObjectHasKeys(server, ["urls"]); utils.checkObjectHasKeys(server, ["urls"]);
} }
this.callId = "c" + new Date().getTime() + Math.random(); this.callId = genCallID();
this.state = CallState.Fledgling; this.state = CallState.Fledgling;
// A queue for candidates waiting to go out. // A queue for candidates waiting to go out.
@@ -358,6 +368,10 @@ export class MatrixCall extends EventEmitter {
return this.opponentMember; return this.opponentMember;
} }
opponentCanBeTransferred() {
return Boolean(this.opponentCaps && this.opponentCaps["m.call.transferee"]);
}
/** /**
* Retrieve the local <code>&lt;video&gt;</code> DOM element. * Retrieve the local <code>&lt;video&gt;</code> DOM element.
* @return {Element} The dom element * @return {Element} The dom element
@@ -469,7 +483,11 @@ export class MatrixCall extends EventEmitter {
this.setState(CallState.Ringing); this.setState(CallState.Ringing);
this.opponentVersion = this.msg.version; this.opponentVersion = this.msg.version;
if (this.opponentVersion !== 0) {
// ignore party ID in v0 calls: party ID isn't a thing until v1
this.opponentPartyId = this.msg.party_id || null; this.opponentPartyId = this.msg.party_id || null;
}
this.opponentCaps = this.msg.capabilities || {};
this.opponentMember = event.sender; this.opponentMember = event.sender;
if (event.getLocalAge()) { if (event.getLocalAge()) {
@@ -779,7 +797,14 @@ export class MatrixCall extends EventEmitter {
// required to still be sent for backwards compat // required to still be sent for backwards compat
type: this.peerConn.localDescription.type, type: this.peerConn.localDescription.type,
}, },
}; } as any;
if (this.client._supportsTransfer) {
answerContent.capabilities = {
'm.call.transferee': true,
}
}
// We have just taken the local description from the peerconnection which will // We have just taken the local description from the peerconnection which will
// contain all the local candidates added so far, so we can discard any candidates // contain all the local candidates added so far, so we can discard any candidates
// we had queued up because they'll be in the answer. // we had queued up because they'll be in the answer.
@@ -959,7 +984,10 @@ export class MatrixCall extends EventEmitter {
} }
this.opponentVersion = event.getContent().version; this.opponentVersion = event.getContent().version;
if (this.opponentVersion !== 0) {
this.opponentPartyId = event.getContent().party_id || null; this.opponentPartyId = event.getContent().party_id || null;
}
this.opponentCaps = event.getContent().capabilities || {};
this.opponentMember = event.sender; this.opponentMember = event.sender;
this.setState(CallState.Connecting); this.setState(CallState.Connecting);
@@ -1102,7 +1130,13 @@ export class MatrixCall extends EventEmitter {
const content = { const content = {
[keyName]: this.peerConn.localDescription, [keyName]: this.peerConn.localDescription,
lifetime: CALL_TIMEOUT_MS, lifetime: CALL_TIMEOUT_MS,
}; } as any;
if (this.client._supportsTransfer) {
content.capabilities = {
'm.call.transferee': true,
}
}
// Get rid of any candidates waiting to be sent: they'll be included in the local // Get rid of any candidates waiting to be sent: they'll be included in the local
// description we just got and will send in the offer. // description we just got and will send in the offer.
@@ -1379,6 +1413,28 @@ export class MatrixCall extends EventEmitter {
} }
} }
async transfer(targetUserId: string, targetRoomId?: string) {
// Fetch the target user's global profile info: their room avatar / displayname
// could be different in whatever room we shae with them.
const profileInfo = await this.client.getProfileInfo(targetUserId);
const replacementId = genCallID();
const body = {
replacement_id: genCallID(),
target_user: {
id: targetUserId,
display_name: profileInfo.display_name,
avatar_url: profileInfo.avatar_url,
},
create_call: replacementId,
} as any;
if (targetRoomId) body.target_room = targetRoomId;
return this.sendVoipEvent(EventType.CallReplaces, body);
}
private async terminate(hangupParty: CallParty, hangupReason: CallErrorCode, shouldEmit: boolean) { private async terminate(hangupParty: CallParty, hangupReason: CallErrorCode, shouldEmit: boolean) {
if (this.callHasEnded()) return; if (this.callHasEnded()) return;