Merge branch 'livekit' into valere/initial_mute_states

This commit is contained in:
Valere
2026-01-12 19:13:40 +01:00
52 changed files with 1666 additions and 764 deletions

View File

@@ -19,6 +19,7 @@ export enum ErrorCode {
INSUFFICIENT_CAPACITY_ERROR = "INSUFFICIENT_CAPACITY_ERROR",
E2EE_NOT_SUPPORTED = "E2EE_NOT_SUPPORTED",
OPEN_ID_ERROR = "OPEN_ID_ERROR",
NO_MATRIX_2_AUTHORIZATION_SERVICE = "NO_MATRIX_2_0_AUTHORIZATION_SERVICE",
SFU_ERROR = "SFU_ERROR",
UNKNOWN_ERROR = "UNKNOWN_ERROR",
}
@@ -171,6 +172,23 @@ export class FailToGetOpenIdToken extends ElementCallError {
}
}
export class NoMatrix2AuthorizationService extends ElementCallError {
/**
* Creates an instance of NoMatrix2_0AuthorizationService.
* @param error - The underlying error that caused the failure.
*/
public constructor(error: Error) {
super(
t("error.generic"),
ErrorCode.NO_MATRIX_2_AUTHORIZATION_SERVICE,
ErrorCategory.CONFIGURATION_ISSUE,
t("error.no_matrix_2_authorization_service"),
// Properly set it as a cause for a better reporting on sentry
error,
);
}
}
/**
* Error indicating a failure to start publishing on a LiveKit connection.
*/

View File

@@ -17,14 +17,16 @@ export const localRtcMemberDevice2 = mockRtcMembership(
"2222",
);
export const local = mockMatrixRoomMember(localRtcMember);
// export const localParticipant = mockLocalParticipant({ identity: "" });
export const localId = `${local.userId}:${localRtcMember.deviceId}`;
export const aliceRtcMember = mockRtcMembership("@alice:example.org", "AAAA");
export const aliceDeviceId = "AAAA";
export const aliceUserId = "@alice:example.org";
export const aliceId = `${aliceUserId}:${aliceDeviceId}`;
export const aliceRtcMember = mockRtcMembership(aliceUserId, aliceDeviceId);
export const alice = mockMatrixRoomMember(aliceRtcMember, {
rawDisplayName: "Alice",
});
export const aliceId = `${alice.userId}:${aliceRtcMember.deviceId}`;
export const aliceParticipant = mockRemoteParticipant({ identity: aliceId });
export const aliceDoppelgangerRtcMember = mockRtcMembership(
@@ -38,11 +40,13 @@ export const aliceDoppelganger = mockMatrixRoomMember(
},
);
export const bobRtcMember = mockRtcMembership("@bob:example.org", "BBBB");
export const bobDeviceId = "BBBB";
export const bobUserId = "@bob:example.org";
export const bobId = `${bobUserId}:${bobDeviceId}`;
export const bobRtcMember = mockRtcMembership(bobUserId, bobDeviceId);
export const bob = mockMatrixRoomMember(bobRtcMember, {
rawDisplayName: "Bob",
});
export const bobId = `${bob.userId}:${bobRtcMember.deviceId}`;
export const bobZeroWidthSpaceRtcMember = mockRtcMembership(
"@bob2:example.org",

View File

@@ -50,6 +50,7 @@ import {
type KeyTransportEvents,
type KeyTransportEventsHandlerMap,
} from "matrix-js-sdk/lib/matrixrtc/IKeyTransport";
import { type CallMembershipIdentityParts } from "matrix-js-sdk/lib/matrixrtc/EncryptionManager";
import {
LocalUserMediaViewModel,
@@ -201,40 +202,30 @@ export const exampleTransport: LivekitTransport = {
livekit_alias: "!alias:example.org",
};
export function mockCallMembership(
userId: string,
deviceId: string,
transport?: Transport,
): CallMembership {
const t = transport ?? transportForUser(userId);
return {
userId: userId,
deviceId: deviceId,
getTransport: vi.fn().mockReturnValue(t),
transports: [t],
} as unknown as CallMembership;
}
function transportForUser(userId: string): Transport {
const domain = userId.split(":")[1];
return {
type: "livekit",
livekit_service_url: `https://lk.${domain}`,
livekit_alias: `!alias:${domain}`,
};
}
export function mockRtcMembership(
user: string | RoomMember,
deviceId: string,
callId = "",
fociPreferred: Transport[] = [exampleTransport],
focusActive: LivekitFocusSelection = {
type: "livekit",
focus_selection: "oldest_membership",
customOverwrites?: {
rtcBackendIdentity?: string;
callId?: string;
fociPreferred?: Transport[];
focusActive?: LivekitFocusSelection;
membership?: Partial<SessionMembershipData>;
},
membership: Partial<SessionMembershipData> = {},
): CallMembership {
// setup defaults based on overwrites and fallback values.
const { rtcBackendIdentity, callId, fociPreferred, focusActive, membership } =
{
fociPreferred: [exampleTransport],
focusActive: {
type: "livekit" as const,
focus_selection: "oldest_membership" as const,
},
callId: "",
membership: {},
...customOverwrites,
};
const data: SessionMembershipData = {
application: "m.call",
call_id: callId,
@@ -243,17 +234,29 @@ export function mockRtcMembership(
focus_active: focusActive,
...membership,
};
const userId = typeof user === "string" ? user : user.userId;
const event = new MatrixEvent({
sender: typeof user === "string" ? user : user.userId,
sender: userId,
event_id: `$-ev-${randomUUID()}:example.org`,
content: data,
});
const cms = new CallMembership(event, data);
const membershipData = CallMembership.membershipDataFromMatrixEvent(event);
const cms = new CallMembership(
event,
membershipData,
rtcBackendIdentity ?? `${userId}:${deviceId}`,
);
vi.mocked(cms).getTransport = vi.fn().mockReturnValue(fociPreferred[0]);
return cms;
}
export const ownMemberMock: CallMembershipIdentityParts = {
userId: "@alice:example.org",
deviceId: "DEVICE",
memberId: "@alice:example.org:DEVICE",
};
// Maybe it'd be good to move this to matrix-js-sdk? Our testing needs are
// rather simple, but if one util to mock a member is good enough for us, maybe
// it's useful for matrix-js-sdk consumers in general.
@@ -331,6 +334,7 @@ export function createLocalMedia(
testScope(),
"local",
member.userId,
rtcMember.rtcBackendIdentity,
constant(localParticipant),
{
kind: E2eeType.PER_PARTICIPANT,
@@ -376,6 +380,7 @@ export function createRemoteMedia(
testScope(),
"remote",
member.userId,
rtcMember.rtcBackendIdentity,
constant(participant),
{
kind: E2eeType.PER_PARTICIPANT,
@@ -478,7 +483,7 @@ export class MockRTCSession extends TypedEventEmitter<
if (value !== prev) this.emit(MembershipManagerEvent.ProbablyLeft, value);
}
public async joinRoomSession(): Promise<void> {
public async joinRTCSession(): Promise<void> {
return Promise.resolve();
}
}