1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-25 05:23:13 +03:00
This commit is contained in:
Robin
2024-11-19 09:55:12 -05:00
parent 2f1d654f14
commit 41a2f477d5
7 changed files with 40 additions and 109 deletions

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { isLivekitFocus, isLivekitFocusActive, isLivekitFocusConfig } from "../../../src/matrixrtc/LivekitFocus"; import { isLivekitFocus, isLivekitFocusSelection, isLivekitFocusConfig } from "../../../src/matrixrtc/LivekitFocus";
describe("LivekitFocus", () => { describe("LivekitFocus", () => {
it("isLivekitFocus", () => { it("isLivekitFocus", () => {
@@ -38,13 +38,13 @@ describe("LivekitFocus", () => {
}); });
it("isLivekitFocusActive", () => { it("isLivekitFocusActive", () => {
expect( expect(
isLivekitFocusActive({ isLivekitFocusSelection({
type: "livekit", type: "livekit",
focus_selection: "oldest_membership", focus_selection: "oldest_membership",
}), }),
).toBeTruthy(); ).toBeTruthy();
expect(isLivekitFocusActive({ type: "livekit" })).toBeFalsy(); expect(isLivekitFocusSelection({ type: "livekit" })).toBeFalsy();
expect(isLivekitFocusActive({ type: "not-livekit", focus_selection: "oldest_membership" })).toBeFalsy(); expect(isLivekitFocusSelection({ type: "not-livekit", focus_selection: "oldest_membership" })).toBeFalsy();
}); });
it("isLivekitFocusConfig", () => { it("isLivekitFocusConfig", () => {
expect( expect(

View File

@@ -247,7 +247,7 @@ describe("MatrixRTCSession", () => {
type: "livekit", type: "livekit",
focus_selection: "oldest_membership", focus_selection: "oldest_membership",
}); });
expect(sess.getActiveFocus()).toBe(firstPreferredFocus); expect(sess.resolveActiveFocus()).toBe(firstPreferredFocus);
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", () => {
@@ -267,7 +267,7 @@ describe("MatrixRTCSession", () => {
type: "livekit", type: "livekit",
focus_selection: "unknown", focus_selection: "unknown",
}); });
expect(sess.getActiveFocus()).toBe(undefined); expect(sess.resolveActiveFocus()).toBe(undefined);
}); });
}); });

View File

@@ -17,7 +17,6 @@ limitations under the License.
import { type MatrixEvent } from "../matrix.ts"; import { type MatrixEvent } from "../matrix.ts";
import { deepCompare } from "../utils.ts"; import { deepCompare } from "../utils.ts";
import { type Focus } from "./focus.ts"; import { type Focus } from "./focus.ts";
import { isLivekitFocusActive } from "./LivekitFocus.ts";
import { type SessionDescription } from "./MatrixRTCSession.ts"; import { type SessionDescription } from "./MatrixRTCSession.ts";
/** /**
@@ -61,7 +60,7 @@ export type SessionMembershipData = {
* A list of possible foci this uses knows about. One of them might be used based on the focus_active * A list of possible foci this uses knows about. One of them might be used based on the focus_active
* selection system. * selection system.
*/ */
foci_preferred: Focus[]; foci_preferred?: Focus[];
/** /**
* Optional field that contains the creation of the session. If it is undefined the creation * Optional field that contains the creation of the session. If it is undefined the creation
@@ -195,13 +194,10 @@ export class CallMembership {
} }
public getPreferredFoci(): Focus[] { public getPreferredFoci(): Focus[] {
return this.membershipData.foci_preferred; return this.membershipData.foci_preferred ?? [];
} }
public getFocusSelection(): string | undefined { public getFocusActive(): Focus {
const focusActive = this.membershipData.focus_active; return this.membershipData.focus_active;
if (isLivekitFocusActive(focusActive)) {
return focusActive.focus_selection;
}
} }
} }

View File

@@ -96,8 +96,7 @@ export interface IMembershipManager
*/ */
onRTCSessionMemberUpdate(memberships: CallMembership[]): Promise<void>; onRTCSessionMemberUpdate(memberships: CallMembership[]): Promise<void>;
/** /**
* The used active focus in the currently joined session. * Determines the active focus used by the given session member, or undefined if not joined.
* @returns the used active focus in the currently joined session or undefined if not joined.
*/ */
getActiveFocus(): Focus | undefined; resolveActiveFocus(member: CallMembership): Focus | undefined;
} }

View File

@@ -31,9 +31,9 @@ export interface LivekitFocus extends LivekitFocusConfig {
export const isLivekitFocus = (object: any): object is LivekitFocus => export const isLivekitFocus = (object: any): object is LivekitFocus =>
isLivekitFocusConfig(object) && "livekit_alias" in object; isLivekitFocusConfig(object) && "livekit_alias" in object;
export interface LivekitFocusActive extends Focus { export interface LivekitFocusSelection extends Focus {
type: "livekit"; type: "livekit";
focus_selection: "oldest_membership"; focus_selection: "oldest_membership";
} }
export const isLivekitFocusActive = (object: any): object is LivekitFocusActive => export const isLivekitFocusSelection = (object: any): object is LivekitFocusSelection =>
object.type === "livekit" && "focus_selection" in object; object.type === "livekit" && "focus_selection" in object;

View File

@@ -606,28 +606,14 @@ export class MatrixRTCSession extends TypedEventEmitter<
* @returns The focus that is currently in use to connect to this session. This is undefined * @returns The focus that is currently in use to connect to this session. This is undefined
* if the client is not connected to this session. * if the client is not connected to this session.
*/ */
public getActiveFocus(): Focus | undefined { public resolveActiveFocus(member: CallMembership): Focus | undefined {
return this.membershipManager?.getActiveFocus(); return this.membershipManager?.resolveActiveFocus(member);
} }
public getOldestMembership(): CallMembership | undefined { public getOldestMembership(): CallMembership | undefined {
return this.memberships[0]; return this.memberships[0];
} }
/**
* This method is used when the user is not yet connected to the Session but wants to know what focus
* the users in the session are using to make a decision how it wants/should connect.
*
* See also `getActiveFocus`
* @returns The focus which should be used when joining this session.
*/
public getFocusInUse(): Focus | undefined {
const oldestMembership = this.getOldestMembership();
if (oldestMembership?.getFocusSelection() === "oldest_membership") {
return oldestMembership.getPreferredFoci()[0];
}
}
/** /**
* Re-emit an EncryptionKeyChanged event for each tracked encryption key. This can be used to export * Re-emit an EncryptionKeyChanged event for each tracked encryption key. This can be used to export
* the keys. * the keys.

View File

@@ -17,65 +17,18 @@ import { AbortError } from "p-retry";
import { EventType } from "../@types/event.ts"; import { EventType } from "../@types/event.ts";
import { UpdateDelayedEventAction } from "../@types/requests.ts"; import { UpdateDelayedEventAction } from "../@types/requests.ts";
import { type MatrixClient } from "../client.ts"; import type { MatrixClient } from "../client.ts";
import { UnsupportedDelayedEventsEndpointError } from "../errors.ts";
import { ConnectionError, HTTPError, MatrixError } from "../http-api/errors.ts"; import { ConnectionError, HTTPError, MatrixError } from "../http-api/errors.ts";
import { type Logger, logger as rootLogger } from "../logger.ts"; import { Room } from "../models/room.ts";
import { type Room } from "../models/room.ts"; import { CallMembership, DEFAULT_EXPIRE_DURATION, SessionMembershipData } from "./CallMembership.ts";
import { type CallMembership, DEFAULT_EXPIRE_DURATION, type SessionMembershipData } from "./CallMembership.ts"; import { Focus } from "./focus.ts";
import { type Focus } from "./focus.ts"; import { isLivekitFocusSelection } from "./LivekitFocus.ts";
import { MembershipConfig, SessionDescription } from "./MatrixRTCSession.ts";
import { TypedEventEmitter, UnsupportedDelayedEventsEndpointError } from "src/matrix.ts";
import { IMembershipManager, MembershipManagerEvent, MembershipManagerEventHandlerMap } from "./IMembershipManager.ts";
import { Logger, logger as rootLogger } from "src/logger.ts";
import { ActionScheduler, ActionUpdate } from "./MembershipManagerActionScheduler.ts";
import { isMyMembership, Status } from "./types.ts"; import { isMyMembership, Status } from "./types.ts";
import { isLivekitFocusActive } from "./LivekitFocus.ts";
import { type SessionDescription, type MembershipConfig } from "./MatrixRTCSession.ts";
import { ActionScheduler, type ActionUpdate } from "./MembershipManagerActionScheduler.ts";
import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
import {
MembershipManagerEvent,
type IMembershipManager,
type MembershipManagerEventHandlerMap,
} from "./IMembershipManager.ts";
/* MembershipActionTypes:
On Join: ───────────────┐ ┌───────────────(1)───────────┐
▼ ▼ │
┌────────────────┐ │
│SendDelayedEvent│ ──────(2)───┐ │
└────────────────┘ │ │
│(3) │ │
▼ │ │
┌─────────────┐ │ │
┌──────(4)───│SendJoinEvent│────(4)─────┐ │ │
│ └─────────────┘ │ │ │
│ ┌─────┐ ┌──────┐ │ │ │
▼ ▼ │ │ ▼ ▼ ▼ │
┌────────────┐ │ │ ┌───────────────────┐ │
│UpdateExpiry│ (s) (s)|RestartDelayedEvent│ │
└────────────┘ │ │ └───────────────────┘ │
│ │ │ │ │ │
└─────┘ └──────┘ └───────┘
On Leave: ───────── STOP ALL ABOVE
┌────────────────────────────────┐
│ SendScheduledDelayedLeaveEvent │
└────────────────────────────────┘
│(5)
┌──────────────┐
│SendLeaveEvent│
└──────────────┘
(1) [Not found error] results in resending the delayed event
(2) [hasMemberEvent = true] Sending the delayed event if we
already have a call member event results jumping to the
RestartDelayedEvent loop directly
(3) [hasMemberEvent = false] if there is not call member event
sending it is the next step
(4) Both (UpdateExpiry and RestartDelayedEvent) actions are
scheduled when successfully sending the state event
(5) Only if delayed event sending failed (fallback)
(s) Successful restart/resend
*/
/** /**
* The different types of actions the MembershipManager can take. * The different types of actions the MembershipManager can take.
@@ -262,22 +215,15 @@ export class MembershipManager
return Promise.resolve(); return Promise.resolve();
} }
public getActiveFocus(): Focus | undefined { public resolveActiveFocus(member: CallMembership): Focus | undefined {
if (this.focusActive) { const data = member.getFocusActive();
// A livekit active focus if (isLivekitFocusSelection(data) && data.focus_selection === "oldest_membership") {
if (isLivekitFocusActive(this.focusActive)) {
if (this.focusActive.focus_selection === "oldest_membership") {
const oldestMembership = this.getOldestMembership();
return oldestMembership?.getPreferredFoci()[0];
}
} else {
this.logger.warn("Unknown own ActiveFocus type. This makes it impossible to connect to an SFU.");
}
} else {
// We do not understand the membership format (could be legacy). We default to oldestMembership
// Once there are other methods this is a hard error!
const oldestMembership = this.getOldestMembership(); const oldestMembership = this.getOldestMembership();
return oldestMembership?.getPreferredFoci()[0]; if (member === oldestMembership) return member.getPreferredFoci()[0];
if (oldestMembership !== undefined) return this.resolveActiveFocus(oldestMembership);
} else {
// This is a fully resolved focus config
return data;
} }
} }
@@ -748,8 +694,12 @@ export class MembershipManager
scope: "m.room", scope: "m.room",
device_id: this.deviceId, device_id: this.deviceId,
expires, expires,
focus_active: { type: "livekit", focus_selection: "oldest_membership" }, ...(this.focusActive === undefined
foci_preferred: this.fociPreferred ?? [], ? {
focus_active: { type: "livekit", focus_selection: "oldest_membership" } as const,
foci_preferred: this.fociPreferred ?? [],
}
: { focus_active: this.focusActive }),
}; };
} }