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
WIP
This commit is contained in:
@@ -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(
|
||||||
|
|||||||
@@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user