1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-08-07 23:02:56 +03:00

Refactor GroupCall participant management

This refactoring brings a number of improvements to GroupCall, which I've unfortunately had to combine into a single commit due to coupling:

- Moves the expiration timestamp field on call membership state to be per-device
- Makes the participants of a group call visible without having to enter the call yourself
- Enables users to join group calls from multiple devices
- Identifies active speakers by their call feed, rather than just their user ID
- Plays nicely with clients that can be in multiple calls in a room at once
- Fixes a memory leak caused by the call retry loop never stopping
- Changes GroupCall to update its state synchronously, and write back to room state asynchronously
  - This was already sort of halfway being done, but now we'd be committing to it
  - Generally improves the robustness of the state machine
  - It means that group call joins will appear instant, in a sense

For many reasons, this is a breaking change.
This commit is contained in:
Robin Townsend
2022-11-21 11:58:27 -05:00
parent dd98d7eb2c
commit f46ecf970c
10 changed files with 735 additions and 668 deletions

View File

@@ -81,10 +81,13 @@ const fakeIncomingCall = async (client: TestClient, call: MatrixCall, version: s
call.getFeeds().push(new CallFeed({
client: client.client,
userId: "remote_user_id",
// @ts-ignore Mock
stream: new MockMediaStream("remote_stream_id", [new MockMediaStreamTrack("remote_tack_id")]),
id: "remote_feed_id",
deviceId: undefined,
stream: new MockMediaStream(
"remote_stream_id", [new MockMediaStreamTrack("remote_tack_id", "audio")],
) as unknown as MediaStream,
purpose: SDPStreamMetadataPurpose.Usermedia,
audioMuted: false,
videoMuted: false,
}));
await callPromise;
};
@@ -447,7 +450,7 @@ describe('Call', function() {
client.client.getRoom = () => {
return {
getMember: (userId) => {
getMember: (userId: string) => {
if (userId === opponentMember.userId) {
return opponentMember;
}
@@ -521,10 +524,12 @@ describe('Call', function() {
it("should correctly generate local SDPStreamMetadata", async () => {
const callPromise = call.placeCallWithCallFeeds([new CallFeed({
client: client.client,
// @ts-ignore Mock
stream: new MockMediaStream("local_stream1", [new MockMediaStreamTrack("track_id", "audio")]),
stream: new MockMediaStream(
"local_stream1", [new MockMediaStreamTrack("track_id", "audio")],
) as unknown as MediaStream,
roomId: call.roomId,
userId: client.getUserId(),
deviceId: undefined,
purpose: SDPStreamMetadataPurpose.Usermedia,
audioMuted: false,
videoMuted: false,
@@ -534,8 +539,10 @@ describe('Call', function() {
call.getOpponentMember = jest.fn().mockReturnValue({ userId: "@bob:bar.uk" });
(call as any).pushNewLocalFeed(
new MockMediaStream("local_stream2", [new MockMediaStreamTrack("track_id", "video")]),
SDPStreamMetadataPurpose.Screenshare, "feed_id2",
new MockMediaStream(
"local_stream2", [new MockMediaStreamTrack("track_id", "video")],
) as unknown as MediaStream,
SDPStreamMetadataPurpose.Screenshare,
);
await call.setMicrophoneMuted(true);
@@ -563,20 +570,18 @@ describe('Call', function() {
new CallFeed({
client: client.client,
userId: client.getUserId(),
// @ts-ignore Mock
stream: localUsermediaStream,
deviceId: undefined,
stream: localUsermediaStream as unknown as MediaStream,
purpose: SDPStreamMetadataPurpose.Usermedia,
id: "local_usermedia_feed_id",
audioMuted: false,
videoMuted: false,
}),
new CallFeed({
client: client.client,
userId: client.getUserId(),
// @ts-ignore Mock
stream: localScreensharingStream,
deviceId: undefined,
stream: localScreensharingStream as unknown as MediaStream,
purpose: SDPStreamMetadataPurpose.Screenshare,
id: "local_screensharing_feed_id",
audioMuted: false,
videoMuted: false,
}),