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.
*/
import { isLivekitFocus, isLivekitFocusActive, isLivekitFocusConfig } from "../../../src/matrixrtc/LivekitFocus";
import { isLivekitFocus, isLivekitFocusSelection, isLivekitFocusConfig } from "../../../src/matrixrtc/LivekitFocus";
describe("LivekitFocus", () => {
it("isLivekitFocus", () => {
@@ -38,13 +38,13 @@ describe("LivekitFocus", () => {
});
it("isLivekitFocusActive", () => {
expect(
isLivekitFocusActive({
isLivekitFocusSelection({
type: "livekit",
focus_selection: "oldest_membership",
}),
).toBeTruthy();
expect(isLivekitFocusActive({ type: "livekit" })).toBeFalsy();
expect(isLivekitFocusActive({ type: "not-livekit", focus_selection: "oldest_membership" })).toBeFalsy();
expect(isLivekitFocusSelection({ type: "livekit" })).toBeFalsy();
expect(isLivekitFocusSelection({ type: "not-livekit", focus_selection: "oldest_membership" })).toBeFalsy();
});
it("isLivekitFocusConfig", () => {
expect(

View File

@@ -247,7 +247,7 @@ describe("MatrixRTCSession", () => {
type: "livekit",
focus_selection: "oldest_membership",
});
expect(sess.getActiveFocus()).toBe(firstPreferredFocus);
expect(sess.resolveActiveFocus()).toBe(firstPreferredFocus);
jest.useRealTimers();
});
it("does not provide focus if the selection method is unknown", () => {
@@ -267,7 +267,7 @@ describe("MatrixRTCSession", () => {
type: "livekit",
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 { deepCompare } from "../utils.ts";
import { type Focus } from "./focus.ts";
import { isLivekitFocusActive } from "./LivekitFocus.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
* selection system.
*/
foci_preferred: Focus[];
foci_preferred?: Focus[];
/**
* 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[] {
return this.membershipData.foci_preferred;
return this.membershipData.foci_preferred ?? [];
}
public getFocusSelection(): string | undefined {
const focusActive = this.membershipData.focus_active;
if (isLivekitFocusActive(focusActive)) {
return focusActive.focus_selection;
}
public getFocusActive(): Focus {
return this.membershipData.focus_active;
}
}

View File

@@ -96,8 +96,7 @@ export interface IMembershipManager
*/
onRTCSessionMemberUpdate(memberships: CallMembership[]): Promise<void>;
/**
* The used active focus in the currently joined session.
* @returns the used active focus in the currently joined session or undefined if not joined.
* Determines the active focus used by the given session member, 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 =>
isLivekitFocusConfig(object) && "livekit_alias" in object;
export interface LivekitFocusActive extends Focus {
export interface LivekitFocusSelection extends Focus {
type: "livekit";
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;

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
* if the client is not connected to this session.
*/
public getActiveFocus(): Focus | undefined {
return this.membershipManager?.getActiveFocus();
public resolveActiveFocus(member: CallMembership): Focus | undefined {
return this.membershipManager?.resolveActiveFocus(member);
}
public getOldestMembership(): CallMembership | undefined {
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
* the keys.

View File

@@ -17,65 +17,18 @@ import { AbortError } from "p-retry";
import { EventType } from "../@types/event.ts";
import { UpdateDelayedEventAction } from "../@types/requests.ts";
import { type MatrixClient } from "../client.ts";
import { UnsupportedDelayedEventsEndpointError } from "../errors.ts";
import type { MatrixClient } from "../client.ts";
import { ConnectionError, HTTPError, MatrixError } from "../http-api/errors.ts";
import { type Logger, logger as rootLogger } from "../logger.ts";
import { type Room } from "../models/room.ts";
import { type CallMembership, DEFAULT_EXPIRE_DURATION, type SessionMembershipData } from "./CallMembership.ts";
import { type Focus } from "./focus.ts";
import { Room } from "../models/room.ts";
import { CallMembership, DEFAULT_EXPIRE_DURATION, SessionMembershipData } from "./CallMembership.ts";
import { 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 { 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.
@@ -262,22 +215,15 @@ export class MembershipManager
return Promise.resolve();
}
public getActiveFocus(): Focus | undefined {
if (this.focusActive) {
// A livekit active focus
if (isLivekitFocusActive(this.focusActive)) {
if (this.focusActive.focus_selection === "oldest_membership") {
public resolveActiveFocus(member: CallMembership): Focus | undefined {
const data = member.getFocusActive();
if (isLivekitFocusSelection(data) && data.focus_selection === "oldest_membership") {
const oldestMembership = this.getOldestMembership();
return oldestMembership?.getPreferredFoci()[0];
}
if (member === oldestMembership) return member.getPreferredFoci()[0];
if (oldestMembership !== undefined) return this.resolveActiveFocus(oldestMembership);
} 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();
return oldestMembership?.getPreferredFoci()[0];
// This is a fully resolved focus config
return data;
}
}
@@ -748,8 +694,12 @@ export class MembershipManager
scope: "m.room",
device_id: this.deviceId,
expires,
focus_active: { type: "livekit", focus_selection: "oldest_membership" },
...(this.focusActive === undefined
? {
focus_active: { type: "livekit", focus_selection: "oldest_membership" } as const,
foci_preferred: this.fociPreferred ?? [],
}
: { focus_active: this.focusActive }),
};
}