1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-08-09 10:22:46 +03:00

Add the call object to Call events

As explained in the comment. I've added it to the end so this should
be completely backwards compatible (although it would be much nicer
if it were the first arg, probably).
This commit is contained in:
David Baker
2023-03-24 14:09:22 +00:00
parent 254f043ab0
commit d7b75e4b9e
4 changed files with 75 additions and 47 deletions

View File

@@ -737,7 +737,7 @@ describe("Call", function () {
const dataChannel = call.createDataChannel("data_channel_label", { id: 123 }); const dataChannel = call.createDataChannel("data_channel_label", { id: 123 });
expect(dataChannelCallback).toHaveBeenCalledWith(dataChannel); expect(dataChannelCallback).toHaveBeenCalledWith(dataChannel, call);
expect(dataChannel.label).toBe("data_channel_label"); expect(dataChannel.label).toBe("data_channel_label");
expect(dataChannel.id).toBe(123); expect(dataChannel.id).toBe(123);
}); });
@@ -1604,7 +1604,7 @@ describe("Call", function () {
hasAdvancedBy += advanceBy; hasAdvancedBy += advanceBy;
expect(lengthChangedListener).toHaveBeenCalledTimes(hasAdvancedBy); expect(lengthChangedListener).toHaveBeenCalledTimes(hasAdvancedBy);
expect(lengthChangedListener).toHaveBeenCalledWith(hasAdvancedBy); expect(lengthChangedListener).toHaveBeenCalledWith(hasAdvancedBy, call);
} }
}); });

View File

@@ -102,7 +102,7 @@ describe("CallFeed", () => {
[CallState.Connected, true], [CallState.Connected, true],
[CallState.Connecting, false], [CallState.Connecting, false],
])("should react to call state, when !isLocal()", (state: CallState, expected: Boolean) => { ])("should react to call state, when !isLocal()", (state: CallState, expected: Boolean) => {
call.emit(CallEvent.State, state); call.emit(CallEvent.State, state, CallState.InviteSent, call.typed());
expect(feed.connected).toBe(expected); expect(feed.connected).toBe(expected);
}); });

View File

@@ -792,7 +792,7 @@ describe("Group Call", function () {
call.isLocalVideoMuted = jest.fn().mockReturnValue(true); call.isLocalVideoMuted = jest.fn().mockReturnValue(true);
call.setLocalVideoMuted = jest.fn(); call.setLocalVideoMuted = jest.fn();
call.emit(CallEvent.State, CallState.Connected); call.emit(CallEvent.State, CallState.Connected, CallState.InviteSent, call);
expect(call.setMicrophoneMuted).toHaveBeenCalledWith(false); expect(call.setMicrophoneMuted).toHaveBeenCalledWith(false);
expect(call.setLocalVideoMuted).toHaveBeenCalledWith(false); expect(call.setLocalVideoMuted).toHaveBeenCalledWith(false);
@@ -1080,7 +1080,7 @@ describe("Group Call", function () {
}); });
it("handles regular case", () => { it("handles regular case", () => {
oldMockCall.emit(CallEvent.Replaced, newMockCall.typed()); oldMockCall.emit(CallEvent.Replaced, newMockCall.typed(), oldMockCall.typed());
expect(oldMockCall.hangup).toHaveBeenCalled(); expect(oldMockCall.hangup).toHaveBeenCalled();
expect(callChangedListener).toHaveBeenCalledWith(newCallsMap); expect(callChangedListener).toHaveBeenCalledWith(newCallsMap);
@@ -1091,7 +1091,7 @@ describe("Group Call", function () {
it("handles case where call is missing from the calls map", () => { it("handles case where call is missing from the calls map", () => {
// @ts-ignore // @ts-ignore
groupCall.calls = new Map(); groupCall.calls = new Map();
oldMockCall.emit(CallEvent.Replaced, newMockCall.typed()); oldMockCall.emit(CallEvent.Replaced, newMockCall.typed(), oldMockCall.typed());
expect(oldMockCall.hangup).toHaveBeenCalled(); expect(oldMockCall.hangup).toHaveBeenCalled();
expect(callChangedListener).toHaveBeenCalledWith(newCallsMap); expect(callChangedListener).toHaveBeenCalledWith(newCallsMap);

View File

@@ -296,20 +296,34 @@ export interface VoipEvent {
content: Record<string, unknown>; content: Record<string, unknown>;
} }
/**
* These now all have the call object as an argument. Why? Well, to know which call a given event is
* about you have three options:
* 1. Use a closure as the callback that remembers what call it's listening to. This can be
* a pain because you need to pass the listener function again when you remove the listener,
* which might be somewhere else.
* 2. Use not-very-well-known fact that EventEmitter sets 'this' to the emitter object in the
* callback. This doesn't really play well with modern Typescript and eslint and doesn't work
* with our pattern of re-emitting events.
* 3. Pass the object in question as an argument to the callback.
*
* Now that we have group calls which have to deal with multiple call objects, this will
* become more important, and I think methods 1 and 2 are just going to cause issues.
*/
export type CallEventHandlerMap = { export type CallEventHandlerMap = {
[CallEvent.DataChannel]: (channel: RTCDataChannel) => void; [CallEvent.DataChannel]: (channel: RTCDataChannel, call: MatrixCall) => void;
[CallEvent.FeedsChanged]: (feeds: CallFeed[]) => void; [CallEvent.FeedsChanged]: (feeds: CallFeed[], call: MatrixCall) => void;
[CallEvent.Replaced]: (newCall: MatrixCall) => void; [CallEvent.Replaced]: (newCall: MatrixCall, oldCall: MatrixCall) => void;
[CallEvent.Error]: (error: CallError) => void; [CallEvent.Error]: (error: CallError, call: MatrixCall) => void;
[CallEvent.RemoteHoldUnhold]: (onHold: boolean) => void; [CallEvent.RemoteHoldUnhold]: (onHold: boolean, call: MatrixCall) => void;
[CallEvent.LocalHoldUnhold]: (onHold: boolean) => void; [CallEvent.LocalHoldUnhold]: (onHold: boolean, call: MatrixCall) => void;
[CallEvent.LengthChanged]: (length: number) => void; [CallEvent.LengthChanged]: (length: number, call: MatrixCall) => void;
[CallEvent.State]: (state: CallState, oldState?: CallState) => void; [CallEvent.State]: (state: CallState, oldState: CallState, call: MatrixCall) => void;
[CallEvent.Hangup]: (call: MatrixCall) => void; [CallEvent.Hangup]: (call: MatrixCall) => void;
[CallEvent.AssertedIdentityChanged]: () => void; [CallEvent.AssertedIdentityChanged]: (call: MatrixCall) => void;
/* @deprecated */ /* @deprecated */
[CallEvent.HoldUnhold]: (onHold: boolean) => void; [CallEvent.HoldUnhold]: (onHold: boolean) => void;
[CallEvent.SendVoipEvent]: (event: VoipEvent) => void; [CallEvent.SendVoipEvent]: (event: VoipEvent, call: MatrixCall) => void;
}; };
// The key of the transceiver map (purpose + media type, separated by ':') // The key of the transceiver map (purpose + media type, separated by ':')
@@ -459,7 +473,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
*/ */
public createDataChannel(label: string, options: RTCDataChannelInit | undefined): RTCDataChannel { public createDataChannel(label: string, options: RTCDataChannelInit | undefined): RTCDataChannel {
const dataChannel = this.peerConn!.createDataChannel(label, options); const dataChannel = this.peerConn!.createDataChannel(label, options);
this.emit(CallEvent.DataChannel, dataChannel); this.emit(CallEvent.DataChannel, dataChannel, this);
return dataChannel; return dataChannel;
} }
@@ -494,7 +508,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
private set state(state: CallState) { private set state(state: CallState) {
const oldState = this._state; const oldState = this._state;
this._state = state; this._state = state;
this.emit(CallEvent.State, state, oldState); this.emit(CallEvent.State, state, oldState, this);
} }
public get type(): CallType { public get type(): CallType {
@@ -684,7 +698,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
}), }),
); );
this.emit(CallEvent.FeedsChanged, this.feeds); this.emit(CallEvent.FeedsChanged, this.feeds, this);
logger.info( logger.info(
`Call ${this.callId} pushRemoteFeed() pushed stream (streamId=${stream.id}, active=${stream.active}, purpose=${purpose})`, `Call ${this.callId} pushRemoteFeed() pushed stream (streamId=${stream.id}, active=${stream.active}, purpose=${purpose})`,
@@ -732,7 +746,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
}), }),
); );
this.emit(CallEvent.FeedsChanged, this.feeds); this.emit(CallEvent.FeedsChanged, this.feeds, this);
logger.info( logger.info(
`Call ${this.callId} pushRemoteFeedWithoutMetadata() pushed stream (streamId=${stream.id}, active=${stream.active})`, `Call ${this.callId} pushRemoteFeedWithoutMetadata() pushed stream (streamId=${stream.id}, active=${stream.active})`,
@@ -832,7 +846,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
`Call ${this.callId} pushLocalFeed() pushed stream (id=${callFeed.stream.id}, active=${callFeed.stream.active}, purpose=${callFeed.purpose})`, `Call ${this.callId} pushLocalFeed() pushed stream (id=${callFeed.stream.id}, active=${callFeed.stream.active}, purpose=${callFeed.purpose})`,
); );
this.emit(CallEvent.FeedsChanged, this.feeds); this.emit(CallEvent.FeedsChanged, this.feeds, this);
} }
/** /**
@@ -869,7 +883,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
} }
this.feeds = []; this.feeds = [];
this.emit(CallEvent.FeedsChanged, this.feeds); this.emit(CallEvent.FeedsChanged, this.feeds, this);
} }
private deleteFeedByStream(stream: MediaStream): void { private deleteFeedByStream(stream: MediaStream): void {
@@ -886,7 +900,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
private deleteFeed(feed: CallFeed): void { private deleteFeed(feed: CallFeed): void {
feed.dispose(); feed.dispose();
this.feeds.splice(this.feeds.indexOf(feed), 1); this.feeds.splice(this.feeds.indexOf(feed), 1);
this.emit(CallEvent.FeedsChanged, this.feeds); this.emit(CallEvent.FeedsChanged, this.feeds, this);
} }
// The typescript definitions have this type as 'any' :( // The typescript definitions have this type as 'any' :(
@@ -1117,7 +1131,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
} }
} }
this.successor = newCall; this.successor = newCall;
this.emit(CallEvent.Replaced, newCall); this.emit(CallEvent.Replaced, newCall, this);
this.hangup(CallErrorCode.Replaced, true); this.hangup(CallErrorCode.Replaced, true);
} }
@@ -1188,6 +1202,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
this.emit( this.emit(
CallEvent.Error, CallEvent.Error,
new CallError(CallErrorCode.NoUserMedia, "Failed to get camera access: ", <Error>error), new CallError(CallErrorCode.NoUserMedia, "Failed to get camera access: ", <Error>error),
this,
); );
} }
} }
@@ -1513,7 +1528,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
this.updateMuteStatus(); this.updateMuteStatus();
this.sendMetadataUpdate(); this.sendMetadataUpdate();
this.emit(CallEvent.RemoteHoldUnhold, this.remoteOnHold); this.emit(CallEvent.RemoteHoldUnhold, this.remoteOnHold, this);
} }
/** /**
@@ -1638,7 +1653,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
code = CallErrorCode.UnknownDevices; code = CallErrorCode.UnknownDevices;
message = "Unknown devices present in the room"; message = "Unknown devices present in the room";
} }
this.emit(CallEvent.Error, new CallError(code, message, <Error>error)); this.emit(CallEvent.Error, new CallError(code, message, <Error>error), this);
throw error; throw error;
} }
@@ -1987,7 +2002,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
const newLocalOnHold = this.isLocalOnHold(); const newLocalOnHold = this.isLocalOnHold();
if (prevLocalOnHold !== newLocalOnHold) { if (prevLocalOnHold !== newLocalOnHold) {
this.emit(CallEvent.LocalHoldUnhold, newLocalOnHold); this.emit(CallEvent.LocalHoldUnhold, newLocalOnHold, this);
// also this one for backwards compat // also this one for backwards compat
this.emit(CallEvent.HoldUnhold, newLocalOnHold); this.emit(CallEvent.HoldUnhold, newLocalOnHold);
} }
@@ -2018,7 +2033,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
id: content.asserted_identity.id, id: content.asserted_identity.id,
displayName: content.asserted_identity.display_name, displayName: content.asserted_identity.display_name,
}; };
this.emit(CallEvent.AssertedIdentityChanged); this.emit(CallEvent.AssertedIdentityChanged, this);
} }
public callHasEnded(): boolean { public callHasEnded(): boolean {
@@ -2134,7 +2149,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
message = "Unknown devices present in the room"; message = "Unknown devices present in the room";
} }
this.emit(CallEvent.Error, new CallError(code, message, <Error>error)); this.emit(CallEvent.Error, new CallError(code, message, <Error>error), this);
this.terminate(CallParty.Local, code, false); this.terminate(CallParty.Local, code, false);
// no need to carry on & send the candidate queue, but we also // no need to carry on & send the candidate queue, but we also
@@ -2158,7 +2173,11 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
private getLocalOfferFailed = (err: Error): void => { private getLocalOfferFailed = (err: Error): void => {
logger.error(`Call ${this.callId} getLocalOfferFailed() running`, err); logger.error(`Call ${this.callId} getLocalOfferFailed() running`, err);
this.emit(CallEvent.Error, new CallError(CallErrorCode.LocalOfferFailed, "Failed to get local offer!", err)); this.emit(
CallEvent.Error,
new CallError(CallErrorCode.LocalOfferFailed, "Failed to get local offer!", err),
this,
);
this.terminate(CallParty.Local, CallErrorCode.LocalOfferFailed, false); this.terminate(CallParty.Local, CallErrorCode.LocalOfferFailed, false);
}; };
@@ -2177,6 +2196,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
"Couldn't start capturing media! Is your microphone set up and " + "does this app have permission?", "Couldn't start capturing media! Is your microphone set up and " + "does this app have permission?",
err, err,
), ),
this,
); );
this.terminate(CallParty.Local, CallErrorCode.NoUserMedia, false); this.terminate(CallParty.Local, CallErrorCode.NoUserMedia, false);
}; };
@@ -2200,7 +2220,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
this.callStartTime = Date.now(); this.callStartTime = Date.now();
this.callLengthInterval = setInterval(() => { this.callLengthInterval = setInterval(() => {
this.emit(CallEvent.LengthChanged, Math.round((Date.now() - this.callStartTime!) / 1000)); this.emit(CallEvent.LengthChanged, Math.round((Date.now() - this.callStartTime!) / 1000), this);
}, CALL_LENGTH_INTERVAL); }, CALL_LENGTH_INTERVAL);
} }
} else if (this.peerConn?.iceConnectionState == "failed") { } else if (this.peerConn?.iceConnectionState == "failed") {
@@ -2267,7 +2287,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
}; };
private onDataChannel = (ev: RTCDataChannelEvent): void => { private onDataChannel = (ev: RTCDataChannelEvent): void => {
this.emit(CallEvent.DataChannel, ev.channel); this.emit(CallEvent.DataChannel, ev.channel, this);
}; };
/** /**
@@ -2380,13 +2400,17 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
[ToDeviceMessageId]: uuidv4(), [ToDeviceMessageId]: uuidv4(),
}; };
this.emit(CallEvent.SendVoipEvent, { this.emit(
type: "toDevice", CallEvent.SendVoipEvent,
eventType, {
userId: this.invitee || this.getOpponentMember()?.userId, type: "toDevice",
opponentDeviceId: this.opponentDeviceId, eventType,
content, userId: this.invitee || this.getOpponentMember()?.userId,
}); opponentDeviceId: this.opponentDeviceId,
content,
},
this,
);
const userId = this.invitee || this.getOpponentMember()!.userId; const userId = this.invitee || this.getOpponentMember()!.userId;
if (this.client.getUseE2eForGroupCall()) { if (this.client.getUseE2eForGroupCall()) {
@@ -2415,13 +2439,17 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
}); });
} }
} else { } else {
this.emit(CallEvent.SendVoipEvent, { this.emit(
type: "sendEvent", CallEvent.SendVoipEvent,
eventType, {
roomId: this.roomId, type: "sendEvent",
content: realContent, eventType,
userId: this.invitee || this.getOpponentMember()?.userId, roomId: this.roomId,
}); content: realContent,
userId: this.invitee || this.getOpponentMember()?.userId,
},
this,
);
await this.client.sendEvent(this.roomId!, eventType, realContent); await this.client.sendEvent(this.roomId!, eventType, realContent);
} }
@@ -2670,7 +2698,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
const code = CallErrorCode.SignallingFailed; const code = CallErrorCode.SignallingFailed;
const message = "Signalling failed"; const message = "Signalling failed";
this.emit(CallEvent.Error, new CallError(code, message, <Error>error)); this.emit(CallEvent.Error, new CallError(code, message, <Error>error), this);
this.hangup(code, false); this.hangup(code, false);
return; return;