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
@@ -38,6 +38,8 @@ describe("MatrixRTCSession", () => {
|
|||||||
client.getDeviceId = jest.fn().mockReturnValue("AAAAAAA");
|
client.getDeviceId = jest.fn().mockReturnValue("AAAAAAA");
|
||||||
client.sendEvent = jest.fn().mockResolvedValue({ event_id: "success" });
|
client.sendEvent = jest.fn().mockResolvedValue({ event_id: "success" });
|
||||||
client.decryptEventIfNeeded = jest.fn();
|
client.decryptEventIfNeeded = jest.fn();
|
||||||
|
client.fetchRoomEvent = jest.fn().mockResolvedValue(undefined);
|
||||||
|
client._unstable_sendDelayedStateEvent = jest.fn().mockResolvedValue({ event_id: "success" });
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
@@ -48,10 +50,10 @@ describe("MatrixRTCSession", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("roomSessionForRoom", () => {
|
describe("roomSessionForRoom", () => {
|
||||||
it("creates a room-scoped session from room state", () => {
|
it("creates a room-scoped session from room state", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
|
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess?.memberships.length).toEqual(1);
|
expect(sess?.memberships.length).toEqual(1);
|
||||||
expect(sess?.memberships[0].slotDescription.id).toEqual("");
|
expect(sess?.memberships[0].slotDescription.id).toEqual("");
|
||||||
expect(sess?.memberships[0].scope).toEqual("m.room");
|
expect(sess?.memberships[0].scope).toEqual("m.room");
|
||||||
@@ -61,26 +63,26 @@ describe("MatrixRTCSession", () => {
|
|||||||
expect(sess?.slotDescription.id).toEqual("");
|
expect(sess?.slotDescription.id).toEqual("");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ignores memberships where application is not m.call", () => {
|
it("ignores memberships where application is not m.call", async () => {
|
||||||
const testMembership = Object.assign({}, membershipTemplate, {
|
const testMembership = Object.assign({}, membershipTemplate, {
|
||||||
application: "not-m.call",
|
application: "not-m.call",
|
||||||
});
|
});
|
||||||
const mockRoom = makeMockRoom([testMembership]);
|
const mockRoom = makeMockRoom([testMembership]);
|
||||||
const sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
const sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess?.memberships).toHaveLength(0);
|
expect(sess?.memberships).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ignores memberships where callId is not empty", () => {
|
it("ignores memberships where callId is not empty", async () => {
|
||||||
const testMembership = Object.assign({}, membershipTemplate, {
|
const testMembership = Object.assign({}, membershipTemplate, {
|
||||||
call_id: "not-empty",
|
call_id: "not-empty",
|
||||||
scope: "m.room",
|
scope: "m.room",
|
||||||
});
|
});
|
||||||
const mockRoom = makeMockRoom([testMembership]);
|
const mockRoom = makeMockRoom([testMembership]);
|
||||||
const sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
const sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess?.memberships).toHaveLength(0);
|
expect(sess?.memberships).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ignores expired memberships events", () => {
|
it("ignores expired memberships events", async () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
const expiredMembership = Object.assign({}, membershipTemplate);
|
const expiredMembership = Object.assign({}, membershipTemplate);
|
||||||
expiredMembership.expires = 1000;
|
expiredMembership.expires = 1000;
|
||||||
@@ -88,38 +90,38 @@ describe("MatrixRTCSession", () => {
|
|||||||
const mockRoom = makeMockRoom([membershipTemplate, expiredMembership]);
|
const mockRoom = makeMockRoom([membershipTemplate, expiredMembership]);
|
||||||
|
|
||||||
jest.advanceTimersByTime(2000);
|
jest.advanceTimersByTime(2000);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess?.memberships.length).toEqual(1);
|
expect(sess?.memberships.length).toEqual(1);
|
||||||
expect(sess?.memberships[0].deviceId).toEqual("AAAAAAA");
|
expect(sess?.memberships[0].deviceId).toEqual("AAAAAAA");
|
||||||
jest.useRealTimers();
|
jest.useRealTimers();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ignores memberships events of members not in the room", () => {
|
it("ignores memberships events of members not in the room", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
mockRoom.hasMembershipState = (state) => state === KnownMembership.Join;
|
mockRoom.hasMembershipState = (state) => state === KnownMembership.Join;
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess?.memberships.length).toEqual(0);
|
expect(sess?.memberships.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("honours created_ts", () => {
|
it("honours created_ts", async () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
jest.setSystemTime(500);
|
jest.setSystemTime(500);
|
||||||
const expiredMembership = Object.assign({}, membershipTemplate);
|
const expiredMembership = Object.assign({}, membershipTemplate);
|
||||||
expiredMembership.created_ts = 500;
|
expiredMembership.created_ts = 500;
|
||||||
expiredMembership.expires = 1000;
|
expiredMembership.expires = 1000;
|
||||||
const mockRoom = makeMockRoom([expiredMembership]);
|
const mockRoom = makeMockRoom([expiredMembership]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess?.memberships[0].getAbsoluteExpiry()).toEqual(1500);
|
expect(sess?.memberships[0].getAbsoluteExpiry()).toEqual(1500);
|
||||||
jest.useRealTimers();
|
jest.useRealTimers();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns empty session if no membership events are present", () => {
|
it("returns empty session if no membership events are present", async () => {
|
||||||
const mockRoom = makeMockRoom([]);
|
const mockRoom = makeMockRoom([]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess?.memberships).toHaveLength(0);
|
expect(sess?.memberships).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("safely ignores events with no memberships section", () => {
|
it("safely ignores events with no memberships section", async () => {
|
||||||
const roomId = secureRandomString(8);
|
const roomId = secureRandomString(8);
|
||||||
const event = {
|
const event = {
|
||||||
getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix),
|
getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix),
|
||||||
@@ -150,11 +152,11 @@ describe("MatrixRTCSession", () => {
|
|||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom as unknown as Room, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom as unknown as Room, callSession);
|
||||||
expect(sess.memberships).toHaveLength(0);
|
expect(sess.memberships).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("safely ignores events with junk memberships section", () => {
|
it("safely ignores events with junk memberships section", async () => {
|
||||||
const roomId = secureRandomString(8);
|
const roomId = secureRandomString(8);
|
||||||
const event = {
|
const event = {
|
||||||
getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix),
|
getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix),
|
||||||
@@ -185,29 +187,29 @@ describe("MatrixRTCSession", () => {
|
|||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom as unknown as Room, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom as unknown as Room, callSession);
|
||||||
expect(sess.memberships).toHaveLength(0);
|
expect(sess.memberships).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ignores memberships with no device_id", () => {
|
it("ignores memberships with no device_id", async () => {
|
||||||
const testMembership = Object.assign({}, membershipTemplate);
|
const testMembership = Object.assign({}, membershipTemplate);
|
||||||
(testMembership.device_id as string | undefined) = undefined;
|
(testMembership.device_id as string | undefined) = undefined;
|
||||||
const mockRoom = makeMockRoom([testMembership]);
|
const mockRoom = makeMockRoom([testMembership]);
|
||||||
const sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
const sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess.memberships).toHaveLength(0);
|
expect(sess.memberships).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ignores memberships with no call_id", () => {
|
it("ignores memberships with no call_id", async () => {
|
||||||
const testMembership = Object.assign({}, membershipTemplate);
|
const testMembership = Object.assign({}, membershipTemplate);
|
||||||
(testMembership.call_id as string | undefined) = undefined;
|
(testMembership.call_id as string | undefined) = undefined;
|
||||||
const mockRoom = makeMockRoom([testMembership]);
|
const mockRoom = makeMockRoom([testMembership]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess.memberships).toHaveLength(0);
|
expect(sess.memberships).toHaveLength(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("getOldestMembership", () => {
|
describe("getOldestMembership", () => {
|
||||||
it("returns the oldest membership event", () => {
|
it("returns the oldest membership event", async () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
jest.setSystemTime(4000);
|
jest.setSystemTime(4000);
|
||||||
const mockRoom = makeMockRoom([
|
const mockRoom = makeMockRoom([
|
||||||
@@ -216,7 +218,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }),
|
Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess.getOldestMembership()!.deviceId).toEqual("old");
|
expect(sess.getOldestMembership()!.deviceId).toEqual("old");
|
||||||
jest.useRealTimers();
|
jest.useRealTimers();
|
||||||
});
|
});
|
||||||
@@ -229,7 +231,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
[undefined, "audio", "audio"],
|
[undefined, "audio", "audio"],
|
||||||
["audio", "audio", "audio"],
|
["audio", "audio", "audio"],
|
||||||
["audio", "video", undefined],
|
["audio", "video", undefined],
|
||||||
])("gets correct consensus for %s + %s = %s", (intentA, intentB, result) => {
|
])("gets correct consensus for %s + %s = %s", async (intentA, intentB, result) => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
jest.setSystemTime(4000);
|
jest.setSystemTime(4000);
|
||||||
const mockRoom = makeMockRoom([
|
const mockRoom = makeMockRoom([
|
||||||
@@ -237,7 +239,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
Object.assign({}, membershipTemplate, { "m.call.intent": intentB }),
|
Object.assign({}, membershipTemplate, { "m.call.intent": intentB }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess.getConsensusCallIntent()).toEqual(result);
|
expect(sess.getConsensusCallIntent()).toEqual(result);
|
||||||
jest.useRealTimers();
|
jest.useRealTimers();
|
||||||
});
|
});
|
||||||
@@ -249,7 +251,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
livekit_service_url: "https://active.url",
|
livekit_service_url: "https://active.url",
|
||||||
livekit_alias: "!active:active.url",
|
livekit_alias: "!active:active.url",
|
||||||
};
|
};
|
||||||
it("gets the correct active focus with oldest_membership", () => {
|
it("gets the correct active focus with oldest_membership", async () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
jest.setSystemTime(3000);
|
jest.setSystemTime(3000);
|
||||||
const mockRoom = makeMockRoom([
|
const mockRoom = makeMockRoom([
|
||||||
@@ -262,7 +264,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }),
|
Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
|
|
||||||
sess.joinRoomSession([{ type: "livekit", livekit_service_url: "htts://test.org" }], {
|
sess.joinRoomSession([{ type: "livekit", livekit_service_url: "htts://test.org" }], {
|
||||||
type: "livekit",
|
type: "livekit",
|
||||||
@@ -273,7 +275,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
);
|
);
|
||||||
jest.useRealTimers();
|
jest.useRealTimers();
|
||||||
});
|
});
|
||||||
it("does not provide focus if the selection method is unknown", () => {
|
it("does not provide focus if the selection method is unknown", async () => {
|
||||||
const mockRoom = makeMockRoom([
|
const mockRoom = makeMockRoom([
|
||||||
Object.assign({}, membershipTemplate, {
|
Object.assign({}, membershipTemplate, {
|
||||||
device_id: "foo",
|
device_id: "foo",
|
||||||
@@ -284,7 +286,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }),
|
Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
|
|
||||||
sess.joinRoomSession([{ type: "livekit", livekit_service_url: "htts://test.org" }], {
|
sess.joinRoomSession([{ type: "livekit", livekit_service_url: "htts://test.org" }], {
|
||||||
type: "livekit",
|
type: "livekit",
|
||||||
@@ -300,7 +302,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
let sendStateEventMock: jest.Mock;
|
let sendStateEventMock: jest.Mock;
|
||||||
|
|
||||||
let sentStateEvent: Promise<void>;
|
let sentStateEvent: Promise<void>;
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
sentStateEvent = new Promise((resolve) => {
|
sentStateEvent = new Promise((resolve) => {
|
||||||
sendStateEventMock = jest.fn(resolve);
|
sendStateEventMock = jest.fn(resolve);
|
||||||
});
|
});
|
||||||
@@ -311,7 +313,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
client._unstable_updateDelayedEvent = jest.fn();
|
client._unstable_updateDelayedEvent = jest.fn();
|
||||||
|
|
||||||
mockRoom = makeMockRoom([]);
|
mockRoom = makeMockRoom([]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
@@ -347,8 +349,14 @@ describe("MatrixRTCSession", () => {
|
|||||||
|
|
||||||
sess!.joinRoomSession([mockFocus], mockFocus, { notificationType: "ring" });
|
sess!.joinRoomSession([mockFocus], mockFocus, { notificationType: "ring" });
|
||||||
await Promise.race([sentStateEvent, new Promise((resolve) => setTimeout(resolve, 5000))]);
|
await Promise.race([sentStateEvent, new Promise((resolve) => setTimeout(resolve, 5000))]);
|
||||||
|
const { resolve: r, promise: p } = Promise.withResolvers();
|
||||||
|
sess?.once(MatrixRTCSessionEvent.JoinStateChanged, r);
|
||||||
|
await p;
|
||||||
mockRoomState(mockRoom, [{ ...membershipTemplate, user_id: client.getUserId()! }]);
|
mockRoomState(mockRoom, [{ ...membershipTemplate, user_id: client.getUserId()! }]);
|
||||||
sess!.onRTCSessionMemberUpdate();
|
sess!.onRTCSessionMemberUpdate();
|
||||||
|
const { resolve, promise } = Promise.withResolvers();
|
||||||
|
sess?.once(MatrixRTCSessionEvent.MembershipsChanged, resolve);
|
||||||
|
await promise;
|
||||||
const ownMembershipId = sess?.memberships[0].eventId;
|
const ownMembershipId = sess?.memberships[0].eventId;
|
||||||
|
|
||||||
expect(client.sendEvent).toHaveBeenCalledWith(mockRoom!.roomId, EventType.RTCNotification, {
|
expect(client.sendEvent).toHaveBeenCalledWith(mockRoom!.roomId, EventType.RTCNotification, {
|
||||||
@@ -361,7 +369,6 @@ describe("MatrixRTCSession", () => {
|
|||||||
"lifetime": 30000,
|
"lifetime": 30000,
|
||||||
"sender_ts": expect.any(Number),
|
"sender_ts": expect.any(Number),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check if deprecated notify event is also sent.
|
// Check if deprecated notify event is also sent.
|
||||||
expect(client.sendEvent).toHaveBeenCalledWith(mockRoom!.roomId, EventType.CallNotify, {
|
expect(client.sendEvent).toHaveBeenCalledWith(mockRoom!.roomId, EventType.CallNotify, {
|
||||||
"application": "m.call",
|
"application": "m.call",
|
||||||
@@ -498,9 +505,9 @@ describe("MatrixRTCSession", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("onMembershipsChanged", () => {
|
describe("onMembershipsChanged", () => {
|
||||||
it("does not emit if no membership changes", () => {
|
it("does not emit if no membership changes", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
|
|
||||||
const onMembershipsChanged = jest.fn();
|
const onMembershipsChanged = jest.fn();
|
||||||
sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged);
|
sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged);
|
||||||
@@ -509,9 +516,9 @@ describe("MatrixRTCSession", () => {
|
|||||||
expect(onMembershipsChanged).not.toHaveBeenCalled();
|
expect(onMembershipsChanged).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("emits on membership changes", () => {
|
it("emits on membership changes", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
|
|
||||||
const onMembershipsChanged = jest.fn();
|
const onMembershipsChanged = jest.fn();
|
||||||
sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged);
|
sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged);
|
||||||
@@ -555,7 +562,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
let sendEventMock: jest.Mock;
|
let sendEventMock: jest.Mock;
|
||||||
let sendToDeviceMock: jest.Mock;
|
let sendToDeviceMock: jest.Mock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
sendStateEventMock = jest.fn().mockResolvedValue({ event_id: "id" });
|
sendStateEventMock = jest.fn().mockResolvedValue({ event_id: "id" });
|
||||||
sendDelayedStateMock = jest.fn().mockResolvedValue({ event_id: "id" });
|
sendDelayedStateMock = jest.fn().mockResolvedValue({ event_id: "id" });
|
||||||
sendEventMock = jest.fn().mockResolvedValue({ event_id: "id" });
|
sendEventMock = jest.fn().mockResolvedValue({ event_id: "id" });
|
||||||
@@ -566,7 +573,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
client.encryptAndSendToDevice = sendToDeviceMock;
|
client.encryptAndSendToDevice = sendToDeviceMock;
|
||||||
|
|
||||||
mockRoom = makeMockRoom([]);
|
mockRoom = makeMockRoom([]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
@@ -685,7 +692,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
device_id: "BBBBBBB",
|
device_id: "BBBBBBB",
|
||||||
});
|
});
|
||||||
const mockRoom = makeMockRoom([membershipTemplate, member2]);
|
const mockRoom = makeMockRoom([membershipTemplate, member2]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
|
|
||||||
// joining will trigger an initial key send
|
// joining will trigger an initial key send
|
||||||
const keysSentPromise1 = new Promise<EncryptionKeysEventContent>((resolve) => {
|
const keysSentPromise1 = new Promise<EncryptionKeysEventContent>((resolve) => {
|
||||||
@@ -734,7 +741,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
try {
|
try {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
|
|
||||||
const keysSentPromise1 = new Promise<EncryptionKeysEventContent>((resolve) => {
|
const keysSentPromise1 = new Promise<EncryptionKeysEventContent>((resolve) => {
|
||||||
sendEventMock.mockImplementation((_roomId, _evType, payload) => resolve(payload));
|
sendEventMock.mockImplementation((_roomId, _evType, payload) => resolve(payload));
|
||||||
@@ -785,7 +792,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
const mockRoom = makeMockRoom([member1, member2]);
|
const mockRoom = makeMockRoom([member1, member2]);
|
||||||
mockRoomState(mockRoom, [member1, member2]);
|
mockRoomState(mockRoom, [member1, member2]);
|
||||||
|
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
||||||
|
|
||||||
await keysSentPromise1;
|
await keysSentPromise1;
|
||||||
@@ -830,7 +837,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mockRoom = makeMockRoom([member1, member2]);
|
const mockRoom = makeMockRoom([member1, member2]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
||||||
|
|
||||||
await keysSentPromise1;
|
await keysSentPromise1;
|
||||||
@@ -894,7 +901,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
device_id: "BBBBBBB",
|
device_id: "BBBBBBB",
|
||||||
});
|
});
|
||||||
const mockRoom = makeMockRoom([membershipTemplate, member2]);
|
const mockRoom = makeMockRoom([membershipTemplate, member2]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
|
|
||||||
const onMyEncryptionKeyChanged = jest.fn();
|
const onMyEncryptionKeyChanged = jest.fn();
|
||||||
sess.on(
|
sess.on(
|
||||||
@@ -984,7 +991,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
|
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
// if first time around then set up the session
|
// if first time around then set up the session
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
||||||
} else {
|
} else {
|
||||||
// otherwise update the state reducing the membership each time in order to trigger key rotation
|
// otherwise update the state reducing the membership each time in order to trigger key rotation
|
||||||
@@ -1010,7 +1017,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
try {
|
try {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
|
|
||||||
const keysSentPromise1 = new Promise((resolve) => {
|
const keysSentPromise1 = new Promise((resolve) => {
|
||||||
sendEventMock.mockImplementation(resolve);
|
sendEventMock.mockImplementation(resolve);
|
||||||
@@ -1051,7 +1058,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
|
|
||||||
sess!.joinRoomSession([mockFocus], mockFocus, {
|
sess!.joinRoomSession([mockFocus], mockFocus, {
|
||||||
manageMediaKeys: true,
|
manageMediaKeys: true,
|
||||||
@@ -1074,7 +1081,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
describe("receiving", () => {
|
describe("receiving", () => {
|
||||||
it("collects keys from encryption events", async () => {
|
it("collects keys from encryption events", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
||||||
mockRoom.emitTimelineEvent(
|
mockRoom.emitTimelineEvent(
|
||||||
makeMockEvent("io.element.call.encryption_keys", "@bob:example.org", "1234roomId", {
|
makeMockEvent("io.element.call.encryption_keys", "@bob:example.org", "1234roomId", {
|
||||||
@@ -1099,7 +1106,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
|
|
||||||
it("collects keys at non-zero indices", async () => {
|
it("collects keys at non-zero indices", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
||||||
mockRoom.emitTimelineEvent(
|
mockRoom.emitTimelineEvent(
|
||||||
makeMockEvent("io.element.call.encryption_keys", "@bob:example.org", "1234roomId", {
|
makeMockEvent("io.element.call.encryption_keys", "@bob:example.org", "1234roomId", {
|
||||||
@@ -1125,7 +1132,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
|
|
||||||
it("collects keys by merging", async () => {
|
it("collects keys by merging", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
||||||
mockRoom.emitTimelineEvent(
|
mockRoom.emitTimelineEvent(
|
||||||
makeMockEvent("io.element.call.encryption_keys", "@bob:example.org", "1234roomId", {
|
makeMockEvent("io.element.call.encryption_keys", "@bob:example.org", "1234roomId", {
|
||||||
@@ -1176,7 +1183,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
|
|
||||||
it("ignores older keys at same index", async () => {
|
it("ignores older keys at same index", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
||||||
mockRoom.emitTimelineEvent(
|
mockRoom.emitTimelineEvent(
|
||||||
makeMockEvent(
|
makeMockEvent(
|
||||||
@@ -1235,7 +1242,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
|
|
||||||
it("key timestamps are treated as monotonic", async () => {
|
it("key timestamps are treated as monotonic", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
||||||
mockRoom.emitTimelineEvent(
|
mockRoom.emitTimelineEvent(
|
||||||
makeMockEvent(
|
makeMockEvent(
|
||||||
@@ -1277,9 +1284,9 @@ describe("MatrixRTCSession", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ignores keys event for the local participant", () => {
|
it("ignores keys event for the local participant", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
|
|
||||||
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
||||||
mockRoom.emitTimelineEvent(
|
mockRoom.emitTimelineEvent(
|
||||||
@@ -1302,7 +1309,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
try {
|
try {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
|
|
||||||
// defaults to getTs()
|
// defaults to getTs()
|
||||||
jest.setSystemTime(1000);
|
jest.setSystemTime(1000);
|
||||||
@@ -1356,9 +1363,9 @@ describe("MatrixRTCSession", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("read status", () => {
|
describe("read status", () => {
|
||||||
it("returns the correct probablyLeft status", () => {
|
it("returns the correct probablyLeft status", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess!.probablyLeft).toBe(undefined);
|
expect(sess!.probablyLeft).toBe(undefined);
|
||||||
|
|
||||||
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
||||||
@@ -1372,9 +1379,9 @@ describe("MatrixRTCSession", () => {
|
|||||||
expect(sess!.probablyLeft).toBe(true);
|
expect(sess!.probablyLeft).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns membershipStatus once joinRoomSession got called", () => {
|
it("returns membershipStatus once joinRoomSession got called", async () => {
|
||||||
const mockRoom = makeMockRoom([membershipTemplate]);
|
const mockRoom = makeMockRoom([membershipTemplate]);
|
||||||
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
|
||||||
expect(sess!.membershipStatus).toBe(undefined);
|
expect(sess!.membershipStatus).toBe(undefined);
|
||||||
|
|
||||||
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
import { type Logger, logger as rootLogger } from "../logger.ts";
|
import { type Logger, logger as rootLogger } from "../logger.ts";
|
||||||
import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
|
import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
|
||||||
import { EventTimeline } from "../models/event-timeline.ts";
|
import { EventTimeline } from "../models/event-timeline.ts";
|
||||||
|
import { MatrixEvent } from "../models/event.ts";
|
||||||
import { type Room } from "../models/room.ts";
|
import { type Room } from "../models/room.ts";
|
||||||
import { type MatrixClient } from "../client.ts";
|
import { type MatrixClient } from "../client.ts";
|
||||||
import { EventType, RelationType } from "../@types/event.ts";
|
import { EventType, RelationType } from "../@types/event.ts";
|
||||||
@@ -50,7 +51,6 @@ import {
|
|||||||
} from "./RoomAndToDeviceKeyTransport.ts";
|
} from "./RoomAndToDeviceKeyTransport.ts";
|
||||||
import { TypedReEmitter } from "../ReEmitter.ts";
|
import { TypedReEmitter } from "../ReEmitter.ts";
|
||||||
import { ToDeviceKeyTransport } from "./ToDeviceKeyTransport.ts";
|
import { ToDeviceKeyTransport } from "./ToDeviceKeyTransport.ts";
|
||||||
import { MatrixEvent } from "../models/event.ts";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Events emitted by MatrixRTCSession
|
* Events emitted by MatrixRTCSession
|
||||||
@@ -311,8 +311,9 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|||||||
*/
|
*/
|
||||||
public static async callMembershipsForRoom(
|
public static async callMembershipsForRoom(
|
||||||
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState" | "findEventById" | "client">,
|
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState" | "findEventById" | "client">,
|
||||||
|
client: Pick<MatrixClient, "fetchRoomEvent">,
|
||||||
): Promise<CallMembership[]> {
|
): Promise<CallMembership[]> {
|
||||||
return await MatrixRTCSession.sessionMembershipsForSlot(room, {
|
return await MatrixRTCSession.sessionMembershipsForSlot(room, client, {
|
||||||
id: "",
|
id: "",
|
||||||
application: "m.call",
|
application: "m.call",
|
||||||
});
|
});
|
||||||
@@ -323,9 +324,10 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|||||||
*/
|
*/
|
||||||
public static async sessionMembershipsForRoom(
|
public static async sessionMembershipsForRoom(
|
||||||
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState" | "findEventById" | "client">,
|
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState" | "findEventById" | "client">,
|
||||||
|
client: Pick<MatrixClient, "fetchRoomEvent">,
|
||||||
sessionDescription: SlotDescription,
|
sessionDescription: SlotDescription,
|
||||||
): Promise<CallMembership[]> {
|
): Promise<CallMembership[]> {
|
||||||
return await this.sessionMembershipsForSlot(room, sessionDescription);
|
return await this.sessionMembershipsForSlot(room, client, sessionDescription);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -334,6 +336,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|||||||
*/
|
*/
|
||||||
public static async sessionMembershipsForSlot(
|
public static async sessionMembershipsForSlot(
|
||||||
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState" | "findEventById" | "client">,
|
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState" | "findEventById" | "client">,
|
||||||
|
client: Pick<MatrixClient, "fetchRoomEvent">,
|
||||||
slotDescription: SlotDescription,
|
slotDescription: SlotDescription,
|
||||||
existingMemberships?: CallMembership[],
|
existingMemberships?: CallMembership[],
|
||||||
): Promise<CallMembership[]> {
|
): Promise<CallMembership[]> {
|
||||||
@@ -350,9 +353,18 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|||||||
let membership = existingMemberships?.find((m) => m.eventId === memberEvent.getId());
|
let membership = existingMemberships?.find((m) => m.eventId === memberEvent.getId());
|
||||||
if (!membership) {
|
if (!membership) {
|
||||||
const relatedEventId = memberEvent.relationEventId;
|
const relatedEventId = memberEvent.relationEventId;
|
||||||
|
const getRelatedMatrixEvent = async (): Promise<MatrixEvent | undefined> => {
|
||||||
|
const eventData = await client
|
||||||
|
.fetchRoomEvent(room.roomId, relatedEventId!)
|
||||||
|
.catch((e) =>
|
||||||
|
logger.error(`Could not get related event ${relatedEventId} for call membership`, e),
|
||||||
|
);
|
||||||
|
|
||||||
|
return eventData ? new MatrixEvent(eventData) : undefined;
|
||||||
|
};
|
||||||
const relatedEvent = relatedEventId
|
const relatedEvent = relatedEventId
|
||||||
? room.findEventById(relatedEventId)
|
? room.findEventById(relatedEventId)
|
||||||
: new MatrixEvent(await room.client.fetchRoomEvent(room.roomId, relatedEventId!));
|
: await getRelatedMatrixEvent();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
membership = new CallMembership(memberEvent, relatedEvent);
|
membership = new CallMembership(memberEvent, relatedEvent);
|
||||||
@@ -403,7 +415,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|||||||
* @deprecated Use `MatrixRTCSession.sessionForSlot` with sessionDescription `{ id: "", application: "m.call" }` instead.
|
* @deprecated Use `MatrixRTCSession.sessionForSlot` with sessionDescription `{ id: "", application: "m.call" }` instead.
|
||||||
*/
|
*/
|
||||||
public static async roomSessionForRoom(client: MatrixClient, room: Room): Promise<MatrixRTCSession> {
|
public static async roomSessionForRoom(client: MatrixClient, room: Room): Promise<MatrixRTCSession> {
|
||||||
const callMemberships = await MatrixRTCSession.sessionMembershipsForSlot(room, {
|
const callMemberships = await MatrixRTCSession.sessionMembershipsForSlot(room, client, {
|
||||||
id: "",
|
id: "",
|
||||||
application: "m.call",
|
application: "m.call",
|
||||||
});
|
});
|
||||||
@@ -413,7 +425,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|||||||
/**
|
/**
|
||||||
* @deprecated Use `MatrixRTCSession.sessionForSlot` instead.
|
* @deprecated Use `MatrixRTCSession.sessionForSlot` instead.
|
||||||
*/
|
*/
|
||||||
public static async sessionForRoom(
|
public static sessionForRoom(
|
||||||
client: MatrixClient,
|
client: MatrixClient,
|
||||||
room: Room,
|
room: Room,
|
||||||
slotDescription: SlotDescription,
|
slotDescription: SlotDescription,
|
||||||
@@ -431,7 +443,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|||||||
room: Room,
|
room: Room,
|
||||||
slotDescription: SlotDescription,
|
slotDescription: SlotDescription,
|
||||||
): Promise<MatrixRTCSession> {
|
): Promise<MatrixRTCSession> {
|
||||||
const callMemberships = await MatrixRTCSession.sessionMembershipsForSlot(room, slotDescription);
|
const callMemberships = await MatrixRTCSession.sessionMembershipsForSlot(room, client, slotDescription);
|
||||||
|
|
||||||
return new MatrixRTCSession(client, room, callMemberships, slotDescription);
|
return new MatrixRTCSession(client, room, callMemberships, slotDescription);
|
||||||
}
|
}
|
||||||
@@ -472,6 +484,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|||||||
| "off"
|
| "off"
|
||||||
| "on"
|
| "on"
|
||||||
| "decryptEventIfNeeded"
|
| "decryptEventIfNeeded"
|
||||||
|
| "fetchRoomEvent"
|
||||||
>,
|
>,
|
||||||
private roomSubset: Pick<
|
private roomSubset: Pick<
|
||||||
Room,
|
Room,
|
||||||
@@ -784,14 +797,14 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|||||||
* Call this when the Matrix room members have changed.
|
* Call this when the Matrix room members have changed.
|
||||||
*/
|
*/
|
||||||
public onRoomMemberUpdate = (): void => {
|
public onRoomMemberUpdate = (): void => {
|
||||||
this.recalculateSessionMembers();
|
void this.recalculateSessionMembers();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this when something changed that may impacts the current MatrixRTC members in this session.
|
* Call this when something changed that may impacts the current MatrixRTC members in this session.
|
||||||
*/
|
*/
|
||||||
public onRTCSessionMemberUpdate = (): void => {
|
public onRTCSessionMemberUpdate = (): void => {
|
||||||
this.recalculateSessionMembers();
|
void this.recalculateSessionMembers();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -801,52 +814,54 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|||||||
*
|
*
|
||||||
* This function should be called when the room members or call memberships might have changed.
|
* This function should be called when the room members or call memberships might have changed.
|
||||||
*/
|
*/
|
||||||
private recalculateSessionMembers = (): void => {
|
private recalculateSessionMembers = async (): Promise<void> => {
|
||||||
const oldMemberships = this.memberships;
|
const oldMemberships = this.memberships;
|
||||||
void MatrixRTCSession.sessionMembershipsForSlot(this.room, this.slotDescription, oldMemberships).then(
|
const newMemberships = await MatrixRTCSession.sessionMembershipsForSlot(
|
||||||
(newMemberships) => {
|
this.room,
|
||||||
this.memberships = newMemberships;
|
this.client,
|
||||||
this._slotId = this._slotId ?? this.memberships[0]?.slotId;
|
this.slotDescription,
|
||||||
|
oldMemberships,
|
||||||
const changed =
|
|
||||||
oldMemberships.length != this.memberships.length ||
|
|
||||||
// If they have the same length, this is enough to check "changed"
|
|
||||||
oldMemberships.some((m, i) => !CallMembership.equal(m, this.memberships[i]));
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
this.logger.info(
|
|
||||||
`Memberships for call in room ${this.roomSubset.roomId} have changed: emitting (${this.memberships.length} members)`,
|
|
||||||
);
|
|
||||||
logDurationSync(this.logger, "emit MatrixRTCSessionEvent.MembershipsChanged", () => {
|
|
||||||
this.emit(MatrixRTCSessionEvent.MembershipsChanged, oldMemberships, this.memberships);
|
|
||||||
});
|
|
||||||
|
|
||||||
void this.membershipManager?.onRTCSessionMemberUpdate(this.memberships);
|
|
||||||
// The `ownMembership` will be set when calling `onRTCSessionMemberUpdate`.
|
|
||||||
const ownMembership = this.membershipManager?.ownMembership;
|
|
||||||
if (this.pendingNotificationToSend && ownMembership && oldMemberships.length === 0) {
|
|
||||||
// If we're the first member in the call, we're responsible for
|
|
||||||
// sending the notification event
|
|
||||||
if (ownMembership.eventId && this.joinConfig?.notificationType) {
|
|
||||||
this.sendCallNotify(
|
|
||||||
ownMembership.eventId,
|
|
||||||
this.joinConfig.notificationType,
|
|
||||||
ownMembership.callIntent,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.logger.warn("Own membership eventId is undefined, cannot send call notification");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If anyone else joins the session it is no longer our responsibility to send the notification.
|
|
||||||
// (If we were the joiner we already did sent the notification in the block above.)
|
|
||||||
if (this.memberships.length > 0) this.pendingNotificationToSend = undefined;
|
|
||||||
}
|
|
||||||
// This also needs to be done if `changed` = false
|
|
||||||
// A member might have updated their fingerprint (created_ts)
|
|
||||||
void this.encryptionManager?.onMembershipsUpdate(oldMemberships);
|
|
||||||
|
|
||||||
this.setExpiryTimer();
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
this.memberships = newMemberships;
|
||||||
|
this._slotId = this._slotId ?? this.memberships[0]?.slotId;
|
||||||
|
|
||||||
|
const changed =
|
||||||
|
oldMemberships.length != this.memberships.length ||
|
||||||
|
// If they have the same length, this is enough to check "changed"
|
||||||
|
oldMemberships.some((m, i) => !CallMembership.equal(m, this.memberships[i]));
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
this.logger.info(
|
||||||
|
`Memberships for call in room ${this.roomSubset.roomId} have changed: emitting (${this.memberships.length} members)`,
|
||||||
|
);
|
||||||
|
logDurationSync(this.logger, "emit MatrixRTCSessionEvent.MembershipsChanged", () => {
|
||||||
|
this.emit(MatrixRTCSessionEvent.MembershipsChanged, oldMemberships, this.memberships);
|
||||||
|
});
|
||||||
|
|
||||||
|
void this.membershipManager?.onRTCSessionMemberUpdate(this.memberships);
|
||||||
|
// The `ownMembership` will be set when calling `onRTCSessionMemberUpdate`.
|
||||||
|
const ownMembership = this.membershipManager?.ownMembership;
|
||||||
|
if (this.pendingNotificationToSend && ownMembership && oldMemberships.length === 0) {
|
||||||
|
// If we're the first member in the call, we're responsible for
|
||||||
|
// sending the notification event
|
||||||
|
if (ownMembership.eventId && this.joinConfig?.notificationType) {
|
||||||
|
this.sendCallNotify(
|
||||||
|
ownMembership.eventId,
|
||||||
|
this.joinConfig.notificationType,
|
||||||
|
ownMembership.callIntent,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.logger.warn("Own membership eventId is undefined, cannot send call notification");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If anyone else joins the session it is no longer our responsibility to send the notification.
|
||||||
|
// (If we were the joiner we already did sent the notification in the block above.)
|
||||||
|
if (this.memberships.length > 0) this.pendingNotificationToSend = undefined;
|
||||||
|
}
|
||||||
|
// This also needs to be done if `changed` = false
|
||||||
|
// A member might have updated their fingerprint (created_ts)
|
||||||
|
void this.encryptionManager?.onMembershipsUpdate(oldMemberships);
|
||||||
|
|
||||||
|
this.setExpiryTimer();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,11 +62,11 @@ export class MatrixRTCSessionManager extends TypedEventEmitter<MatrixRTCSessionM
|
|||||||
this.logger = rootLogger.getChild("[MatrixRTCSessionManager]");
|
this.logger = rootLogger.getChild("[MatrixRTCSessionManager]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public start(): void {
|
public async start(): Promise<void> {
|
||||||
// We shouldn't need to null-check here, but matrix-client.spec.ts mocks getRooms
|
// We shouldn't need to null-check here, but matrix-client.spec.ts mocks getRooms
|
||||||
// returning nothing, and breaks tests if you change it to return an empty array :'(
|
// returning nothing, and breaks tests if you change it to return an empty array :'(
|
||||||
for (const room of this.client.getRooms() ?? []) {
|
for (const room of this.client.getRooms() ?? []) {
|
||||||
const session = MatrixRTCSession.sessionForRoom(this.client, room, this.sessionDescription);
|
const session = await MatrixRTCSession.sessionForRoom(this.client, room, this.sessionDescription);
|
||||||
if (session.memberships.length > 0) {
|
if (session.memberships.length > 0) {
|
||||||
this.roomSessions.set(room.roomId, session);
|
this.roomSessions.set(room.roomId, session);
|
||||||
}
|
}
|
||||||
@@ -98,11 +98,11 @@ export class MatrixRTCSessionManager extends TypedEventEmitter<MatrixRTCSessionM
|
|||||||
* Gets the main MatrixRTC session for a room, returning an empty session
|
* Gets the main MatrixRTC session for a room, returning an empty session
|
||||||
* if no members are currently participating
|
* if no members are currently participating
|
||||||
*/
|
*/
|
||||||
public getRoomSession(room: Room): MatrixRTCSession {
|
public async getRoomSession(room: Room): Promise<MatrixRTCSession> {
|
||||||
if (!this.roomSessions.has(room.roomId)) {
|
if (!this.roomSessions.has(room.roomId)) {
|
||||||
this.roomSessions.set(
|
this.roomSessions.set(
|
||||||
room.roomId,
|
room.roomId,
|
||||||
MatrixRTCSession.sessionForRoom(this.client, room, this.sessionDescription),
|
await MatrixRTCSession.sessionForRoom(this.client, room, this.sessionDescription),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ export class MatrixRTCSessionManager extends TypedEventEmitter<MatrixRTCSessionM
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onRoom = (room: Room): void => {
|
private onRoom = (room: Room): void => {
|
||||||
this.refreshRoom(room);
|
void this.refreshRoom(room);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onRoomState = (event: MatrixEvent, _state: RoomState): void => {
|
private onRoomState = (event: MatrixEvent, _state: RoomState): void => {
|
||||||
@@ -121,13 +121,13 @@ export class MatrixRTCSessionManager extends TypedEventEmitter<MatrixRTCSessionM
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event.getType() == EventType.GroupCallMemberPrefix) {
|
if (event.getType() == EventType.GroupCallMemberPrefix) {
|
||||||
this.refreshRoom(room);
|
void this.refreshRoom(room);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private refreshRoom(room: Room): void {
|
private async refreshRoom(room: Room): Promise<void> {
|
||||||
const isNewSession = !this.roomSessions.has(room.roomId);
|
const isNewSession = !this.roomSessions.has(room.roomId);
|
||||||
const session = this.getRoomSession(room);
|
const session = await this.getRoomSession(room);
|
||||||
|
|
||||||
const wasActiveAndKnown = session.memberships.length > 0 && !isNewSession;
|
const wasActiveAndKnown = session.memberships.length > 0 && !isNewSession;
|
||||||
// This needs to be here and the event listener cannot be setup in the MatrixRTCSession,
|
// This needs to be here and the event listener cannot be setup in the MatrixRTCSession,
|
||||||
|
|||||||
Reference in New Issue
Block a user