UNPKG

matrix-js-sdk

Version:
343 lines 18.1 kB
import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; import { type Room } from "../models/room.ts"; import { type MatrixClient } from "../client.ts"; import { CallMembership } from "./CallMembership.ts"; import { type CallMembershipIdentityParts } from "./EncryptionManager.ts"; import type { Statistics, RTCNotificationType, Status, IRTCNotificationContent, RTCCallIntent, Transport, SlotDescription } from "./types.ts"; import { MembershipManagerEvent, type MembershipManagerEventHandlerMap } from "./IMembershipManager.ts"; /** * Events emitted by MatrixRTCSession */ export declare enum MatrixRTCSessionEvent { MembershipsChanged = "memberships_changed", JoinStateChanged = "join_state_changed", EncryptionKeyChanged = "encryption_key_changed", /** The membership manager had to shut down caused by an unrecoverable error */ MembershipManagerError = "membership_manager_error", /** The RTCSession did send a call notification caused by joining the call as the first member */ DidSendCallNotification = "did_send_call_notification" } export type MatrixRTCSessionEventHandlerMap = { [MatrixRTCSessionEvent.MembershipsChanged]: (oldMemberships: CallMembership[], newMemberships: CallMembership[]) => void; [MatrixRTCSessionEvent.JoinStateChanged]: (isJoined: boolean) => void; [MatrixRTCSessionEvent.EncryptionKeyChanged]: (key: Uint8Array<ArrayBuffer>, encryptionKeyIndex: number, membership: CallMembershipIdentityParts, rtcBackendIdentity: string) => void; [MatrixRTCSessionEvent.MembershipManagerError]: (error: unknown) => void; [MatrixRTCSessionEvent.DidSendCallNotification]: (notificationContentNew: { event_id: string; } & IRTCNotificationContent) => void; }; export interface SessionConfig { /** * What kind of notification to send when starting the session. * @default `undefined` (no notification) */ notificationType?: RTCNotificationType; /** * Determines the kind of call this will be. */ callIntent?: RTCCallIntent; } export interface MembershipConfig { /** * The timeout (in milliseconds) after we joined the call, that our membership should expire * unless we have explicitly updated it. * * This is what goes into the m.rtc.member event expiry field and is typically set to a number of hours. */ membershipEventExpiryMs?: number; /** * The time in (in milliseconds) which the manager will prematurely send the updated state event before the membership `expires` time to make sure it * sends the updated state event early enough. * * A headroom of 1000ms and a `membershipExpiryTimeout` of 10000ms would result in the first membership event update after 9s and * a membership event that would be considered expired after 10s. * * This value does not have an effect on the value of `SessionMembershipData.expires`. */ membershipEventExpiryHeadroomMs?: number; /** * The timeout (in milliseconds) with which the deleayed leave event on the server is configured. * After this time the server will set the event to the disconnected stat if it has not received a keep-alive from the client. */ delayedLeaveEventDelayMs?: number; /** * The interval (in milliseconds) in which the client will send membership keep-alives to the server. */ delayedLeaveEventRestartMs?: number; /** * The maximum number of retries that the manager will do for delayed event sending/updating and state event sending when a server rate limit has been hit. */ maximumRateLimitRetryCount?: number; /** * The maximum number of retries that the manager will do for delayed event sending/updating and state event sending when a network error occurs. */ maximumNetworkErrorRetryCount?: number; /** * The time (in milliseconds) after which we will retry a http request if it * failed to send due to a network error. (send membership event, send delayed event, restart delayed event...) */ networkErrorRetryMs?: number; /** * The time (in milliseconds) after which a we consider a delayed event restart http request to have failed. * Setting this to a lower value will result in more frequent retries but also a higher chance of failiour. * * In the presence of network packet loss (hurting TCP connections), the custom delayedEventRestartLocalTimeoutMs * helps by keeping more delayed event reset candidates in flight, * improving the chances of a successful reset. (its is equivalent to the js-sdk `localTimeout` configuration, * but only applies to calls to the `_unstable_restartScheduledDelayedEvent` endpoint * or the `_unstable_updateDelayedEvent` endpoint with a body of `{action:"restart"}`.) */ delayedLeaveEventRestartLocalTimeoutMs?: number; /** * Send membership using sticky events rather than state events. * This also make the client use the new m.rtc.member MSC4354 event format. (instead of m.call.member) * * **WARNING**: This is an unstable feature and not all clients will support it. */ unstableSendStickyEvents?: boolean; } export interface EncryptionConfig { /** * If true, generate and share a media key for this participant, * and emit MatrixRTCSessionEvent.EncryptionKeyChanged when * media keys for other participants become available. */ manageMediaKeys?: boolean; /** * The minimum time (in milliseconds) between each attempt to send encryption key(s). * e.g. if this is set to 1000, then we will send at most one key event every second. * @deprecated - Not used by the new encryption manager. */ updateEncryptionKeyThrottle?: number; /** * Sometimes it is necessary to rotate the encryption key after a membership update. * For performance reasons we might not want to rotate the key immediately but allow future memberships to use the same key. * If 5 people join in a row in less than 5 seconds, we don't want to rotate the key for each of them. * If 5 people leave in a row in less than 5 seconds, we don't want to rotate the key for each of them. * So we do share the key which was already used live for <5s to new joiners. * This does result in a potential leak up to the configured time of call media. * This has to be considered when choosing a value for this property. */ keyRotationGracePeriodMs?: number; /** * The delay (in milliseconds) after a member leaves before we create and publish a new key, because people * tend to leave calls at the same time. * @deprecated - Not used by the new encryption manager. */ makeKeyDelay?: number; /** * The delay (in milliseconds) between sending a new key and starting to encrypt with it. This * gives others a chance to receive the new key to minimize the chance they get media they can't decrypt. * * The higher this value is, the better it is for existing members as they will have a smoother experience. * But it impacts new joiners: They will always have to wait `useKeyDelay` before being able to decrypt the media * (as it will be encrypted with the new key after the delay only), even if the key has already arrived before the delay. */ useKeyDelay?: number; } export type JoinSessionConfig = SessionConfig & MembershipConfig & EncryptionConfig; interface SessionMembershipsForSlotOpts { /** * Listen for incoming sticky member events. If disabled, this session will * ignore any incoming sticky events. */ listenForStickyEvents: boolean; /** * Listen for incoming member state events (legacy). If disabled, this session will * ignore any incoming state events. */ listenForMemberStateEvents: boolean; } /** * A MatrixRTCSession manages the membership & properties of a MatrixRTC session. * This class doesn't deal with media at all, just membership & properties of a session. */ export declare class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent | MembershipManagerEvent, MatrixRTCSessionEventHandlerMap & MembershipManagerEventHandlerMap> { private readonly client; private roomSubset; readonly slotDescription: SlotDescription; private readonly calculateMembershipsOpts?; private membershipManager?; private encryptionManager?; private joinConfig?; private logger; private pendingNotificationToSend; /** * This timeout is responsible to track any expiration. We need to know when we have to start * to ignore other call members. There is no callback for this. This timeout will always be configured to * emit when the next membership expires. */ private expiryTimeout?; memberships: CallMembership[]; /** * Resolves when the session has calculated the initial membership of the session. */ readonly initialMembershipCalculated: Promise<void>; /** * Does membership need to be recalculated? This is set to false upon * recalculation. */ private membershipNeedsRecalculation; /** * The statistics for this session. */ statistics: Statistics; get membershipStatus(): Status | undefined; get probablyLeft(): boolean | undefined; get delayId(): string | undefined; /** * The callId (sessionId) of the call. * * It can be undefined since the callId is only known once the first membership joins. * The callId is the property that, per definition, groups memberships into one call. * @deprecated use `slotId` instead. */ get callId(): string | undefined; /** * The slotId of the call. * `{application}#{appSpecificId}` * It can be undefined since the slotId is only known once the first membership joins. * The slotId is the property that, per definition, groups memberships into one call. */ get slotId(): string | undefined; /** * Returns all the call memberships for a room that match the provided `sessionDescription`, * oldest first. * * By default, this will return *both* sticky and member state events. */ static sessionMembershipsForSlot(room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState" | "_unstable_getStickyEvents">, slotDescription: SlotDescription, options?: SessionMembershipsForSlotOpts): Promise<CallMembership[]>; /** * Return the MatrixRTC session for the room. * This returned session can be used to find out if there are active sessions * for the requested room and `slotDescription`. */ static sessionForSlot(client: MatrixClient, room: Room, slotDescription: SlotDescription, opts?: SessionMembershipsForSlotOpts): MatrixRTCSession; /** * WARN: this can in theory only be a subset of the room with the properties required by * this class. * Outside of tests this most likely will be a full room, however. * @deprecated Relying on a full Room object being available here is an anti-pattern. You should be tracking * the room object in your own code and passing it in when needed. */ get room(): Room; /** * This constructs a room session. When using MatrixRTC inside the js-sdk this is expected * to be used with the MatrixRTCSessionManager exclusively. * * In cases where you don't use the js-sdk but build on top of another Matrix stack this class can be used standalone * to manage a joined MatrixRTC session. * * @param client A subset of the {@link MatrixClient} that lets the session interact with the Matrix room. * @param roomSubset The room this session is attached to. A subset of a js-sdk Room that the session needs. * @param slotDescription The slot description is a virtual address where participants are allowed to meet. * This session will only manage memberships that match this slot description.Sessions are distinct if any of * those properties are distinct: `roomSubset.roomId`, `slotDescription.application`, `slotDescription.id`. * @param calculateMembershipsOpts - Options to configure how memberships are calculated for this session. */ constructor(client: Pick<MatrixClient, "getUserId" | "getDeviceId" | "sendEvent" | "sendStateEvent" | "_unstable_sendDelayedStateEvent" | "_unstable_updateDelayedEvent" | "_unstable_cancelScheduledDelayedEvent" | "_unstable_restartScheduledDelayedEvent" | "_unstable_sendScheduledDelayedEvent" | "_unstable_sendStickyEvent" | "_unstable_sendStickyDelayedEvent" | "cancelPendingEvent" | "encryptAndSendToDevice" | "off" | "on" | "decryptEventIfNeeded">, roomSubset: Pick<Room, "getLiveTimeline" | "roomId" | "getVersion" | "hasMembershipState" | "on" | "off" | "_unstable_getStickyEvents">, slotDescription: SlotDescription, calculateMembershipsOpts?: SessionMembershipsForSlotOpts | undefined); isJoined(): boolean; /** * Performs cleanup & removes timers for client shutdown */ stop(): Promise<void>; private reEmitter; /** * Announces this user and device as joined to the MatrixRTC session, * and continues to update the membership event to keep it valid until * leaveRoomSession() is called * This will not subscribe to updates: remember to call subscribe() separately if * desired. * This method will return immediately and the session will be joined in the background. * @param ownMembershipIdentity the identity of the user and device joining the session. * This will be put into the content.member. * @param fociPreferred the list of preferred foci to use in the joined RTC membership event. * If multiSfuFocus is set, this is only needed if this client wants to publish to multiple transports simultaneously. * @param multiSfuFocus the active focus to use in the joined RTC membership event. Setting this implies the * membership manager will operate in a multi-SFU connection mode. If `undefined`, an `oldest_membership` * transport selection will be used instead. * @param joinConfig - Additional configuration for the joined session. */ joinRTCSession(ownMembershipIdentity: CallMembershipIdentityParts, fociPreferred: Transport[], multiSfuFocus?: Transport, joinConfig?: JoinSessionConfig): void; /** * * @param fociPreferred * @param multiSfuFocus * @param joinConfig * @deprecated use the joinRTCSession method instead */ joinRoomSession(fociPreferred: Transport[], multiSfuFocus?: Transport, joinConfig?: JoinSessionConfig): void; /** * Announces this user and device as having left the MatrixRTC session * and stops scheduled updates. * This will not unsubscribe from updates: remember to call unsubscribe() separately if * desired. * The membership update required to leave the session will retry if it fails. * Without network connection the promise will never resolve. * A timeout can be provided so that there is a guarantee for the promise to resolve. * @returns Whether the membership update was attempted and did not time out. */ leaveRoomSession(timeout?: number | undefined): Promise<boolean>; /** * This returns the focus in use by the oldest membership. * Do not use since this might be just the focus for the oldest membership. others might use a different focus. * @deprecated use `member.getTransport(session.getOldestMembership())` instead for the specific member you want to get the focus for. */ getFocusInUse(): Transport | undefined; getOldestMembership(): CallMembership | undefined; /** * Get the call intent for the current call, based on what members are advertising. If one or more * members disagree on the current call intent, or nobody specifies one then `undefined` is returned. * * If all members that specify a call intent agree, that value is returned. * @returns A call intent, or `undefined` if no consensus or not given. */ getConsensusCallIntent(): RTCCallIntent | undefined; updateCallIntent(callIntent: RTCCallIntent): Promise<void>; /** * Re-emit an EncryptionKeyChanged event for each tracked encryption key. This can be used to export * the keys. */ reemitEncryptionKeys(): void; /** * Sets a timer for the soonest membership expiry */ private setExpiryTimer; /** * Sends notification events to indiciate the call has started. * Note: This does not return a promise, instead scheduling the notification events to be sent. * @param parentEventId Event id linking to your RTC call membership event. * @param notificationType The type of notification to send * @param callIntent The type of call this is (e.g. "audio"). */ private sendCallNotify; /** * Call this when the Matrix room members have changed. */ private readonly onRoomMemberUpdate; /** * Call this when a sticky event update has occured. */ private readonly onStickyEventUpdate; /** * Call this when something changed that may impacts the current MatrixRTC members in this session. */ _onRTCSessionMemberUpdate: () => Promise<void>; private recalculateSessionMembersPromise; /** * Ensures that membership is recalculated when the state of the session may have changed. * Also ensures that only one recalculation is made at a time. * @returns A promise resolving when the state has been recalculated. */ private ensureRecalculateSessionMembers; /** * Call this when anything that could impact rtc memberships has changed: Room Members or RTC members. * * Examines the latest call memberships and handles any encryption key sending or rotation that is needed. * * This function should be called when the room members or call memberships might have changed. */ private readonly recalculateSessionMembers; } export {}; //# sourceMappingURL=MatrixRTCSession.d.ts.map