matrix-js-sdk 43.0.0 → 44.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/lib/matrixrtc/CallMembership.d.ts +30 -25
  3. package/lib/matrixrtc/CallMembership.d.ts.map +1 -1
  4. package/lib/matrixrtc/CallMembership.js +91 -100
  5. package/lib/matrixrtc/CallMembership.js.map +1 -1
  6. package/lib/matrixrtc/EncryptionManager.d.ts +6 -4
  7. package/lib/matrixrtc/EncryptionManager.d.ts.map +1 -1
  8. package/lib/matrixrtc/EncryptionManager.js.map +1 -1
  9. package/lib/matrixrtc/IMembershipManager.d.ts +2 -15
  10. package/lib/matrixrtc/IMembershipManager.d.ts.map +1 -1
  11. package/lib/matrixrtc/IMembershipManager.js.map +1 -1
  12. package/lib/matrixrtc/LivekitTransport.d.ts +36 -7
  13. package/lib/matrixrtc/LivekitTransport.d.ts.map +1 -1
  14. package/lib/matrixrtc/LivekitTransport.js +29 -2
  15. package/lib/matrixrtc/LivekitTransport.js.map +1 -1
  16. package/lib/matrixrtc/MatrixRTCSession.d.ts +12 -51
  17. package/lib/matrixrtc/MatrixRTCSession.d.ts.map +1 -1
  18. package/lib/matrixrtc/MatrixRTCSession.js +10 -66
  19. package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
  20. package/lib/matrixrtc/MembershipManager.d.ts +5 -10
  21. package/lib/matrixrtc/MembershipManager.d.ts.map +1 -1
  22. package/lib/matrixrtc/MembershipManager.js +25 -44
  23. package/lib/matrixrtc/MembershipManager.js.map +1 -1
  24. package/lib/matrixrtc/RTCEncryptionManager.d.ts +8 -8
  25. package/lib/matrixrtc/RTCEncryptionManager.d.ts.map +1 -1
  26. package/lib/matrixrtc/RTCEncryptionManager.js +30 -22
  27. package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
  28. package/lib/matrixrtc/ToDeviceKeyTransport.js +7 -8
  29. package/lib/matrixrtc/ToDeviceKeyTransport.js.map +1 -1
  30. package/lib/matrixrtc/membershipData/rtc.d.ts +8 -13
  31. package/lib/matrixrtc/membershipData/rtc.d.ts.map +1 -1
  32. package/lib/matrixrtc/membershipData/rtc.js +2 -11
  33. package/lib/matrixrtc/membershipData/rtc.js.map +1 -1
  34. package/lib/matrixrtc/membershipData/session.d.ts +6 -2
  35. package/lib/matrixrtc/membershipData/session.d.ts.map +1 -1
  36. package/lib/matrixrtc/membershipData/session.js +3 -0
  37. package/lib/matrixrtc/membershipData/session.js.map +1 -1
  38. package/lib/matrixrtc/types.d.ts +5 -0
  39. package/lib/matrixrtc/types.d.ts.map +1 -1
  40. package/lib/matrixrtc/types.js +5 -0
  41. package/lib/matrixrtc/types.js.map +1 -1
  42. package/lib/models/event-timeline-set.d.ts +9 -2
  43. package/lib/models/event-timeline-set.d.ts.map +1 -1
  44. package/lib/models/event-timeline-set.js +8 -5
  45. package/lib/models/event-timeline-set.js.map +1 -1
  46. package/lib/models/room-sticky-events.d.ts +17 -2
  47. package/lib/models/room-sticky-events.d.ts.map +1 -1
  48. package/lib/models/room-sticky-events.js +88 -47
  49. package/lib/models/room-sticky-events.js.map +1 -1
  50. package/lib/models/room.d.ts +1 -1
  51. package/lib/models/room.d.ts.map +1 -1
  52. package/lib/models/room.js +8 -2
  53. package/lib/models/room.js.map +1 -1
  54. package/lib/models/thread.d.ts.map +1 -1
  55. package/lib/models/thread.js +23 -2
  56. package/lib/models/thread.js.map +1 -1
  57. package/lib/rendezvous/MSC4108SignInWithQR.d.ts +3 -3
  58. package/lib/rendezvous/MSC4108SignInWithQR.d.ts.map +1 -1
  59. package/lib/rendezvous/MSC4108SignInWithQR.js.map +1 -1
  60. package/lib/rendezvous/SignInWithQRFlow.d.ts +95 -0
  61. package/lib/rendezvous/SignInWithQRFlow.d.ts.map +1 -0
  62. package/lib/rendezvous/SignInWithQRFlow.js +3 -0
  63. package/lib/rendezvous/SignInWithQRFlow.js.map +1 -0
  64. package/lib/rendezvous/index.d.ts +1 -0
  65. package/lib/rendezvous/index.d.ts.map +1 -1
  66. package/lib/rendezvous/index.js.map +1 -1
  67. package/lib/rust-crypto/index.js +5 -1
  68. package/lib/rust-crypto/index.js.map +1 -1
  69. package/package.json +3 -3
  70. package/src/matrixrtc/CallMembership.ts +85 -95
  71. package/src/matrixrtc/EncryptionManager.ts +6 -4
  72. package/src/matrixrtc/IMembershipManager.ts +2 -15
  73. package/src/matrixrtc/LivekitTransport.ts +58 -9
  74. package/src/matrixrtc/MatrixRTCSession.ts +21 -80
  75. package/src/matrixrtc/MembershipManager.ts +23 -40
  76. package/src/matrixrtc/RTCEncryptionManager.ts +51 -39
  77. package/src/matrixrtc/ToDeviceKeyTransport.ts +7 -7
  78. package/src/matrixrtc/membershipData/rtc.ts +9 -23
  79. package/src/matrixrtc/membershipData/session.ts +14 -2
  80. package/src/matrixrtc/types.ts +6 -0
  81. package/src/models/event-timeline-set.ts +19 -4
  82. package/src/models/room-sticky-events.ts +92 -58
  83. package/src/models/room.ts +8 -2
  84. package/src/models/thread.ts +25 -3
  85. package/src/rendezvous/MSC4108SignInWithQR.ts +3 -3
  86. package/src/rendezvous/SignInWithQRFlow.ts +117 -0
  87. package/src/rendezvous/index.ts +1 -0
  88. package/src/rust-crypto/index.ts +5 -1
@@ -50,15 +50,6 @@ export interface IMembershipManager extends TypedEventEmitter<
50
50
  MembershipManagerEvent,
51
51
  MembershipManagerEventHandlerMap
52
52
  > {
53
- /**
54
- * If we are trying to join, or have successfully joined the session.
55
- * It does not reflect if the room state is already configured to represent us being joined.
56
- * It only means that the Manager should be trying to connect or to disconnect running.
57
- * The Manager is still running right after isJoined becomes false to send the disconnect events.
58
- * @returns true if we intend to be participating in the MatrixRTC session
59
- * @deprecated This name is confusing and replaced by `isActivated()`. (Returns the same as `isActivated()`)
60
- */
61
- isJoined(): boolean;
62
53
  /**
63
54
  * If the manager is activated. This means it tries to do its job to join the call, resend state events...
64
55
  * It does not imply that the room state is already configured to represent being joined.
@@ -92,14 +83,10 @@ export interface IMembershipManager extends TypedEventEmitter<
92
83
 
93
84
  /**
94
85
  * Start sending all necessary events to make this user participate in the RTC session.
95
- * @param fociPreferred the list of preferred foci to use in the joined RTC membership event.
96
- * If multiSfuFocus is set, this is only needed if this client wants to publish to multiple transports simultaneously.
97
- * @param multiSfuFocus the active focus to use in the joined RTC membership event. Setting this implies the
98
- * membership manager will operate in a multi-SFU connection mode. If `undefined`, an `oldest_membership`
99
- * transport selection will be used instead.
86
+ * @param publishedTransports the list of transports on which the member is publishing.
100
87
  * @throws can throw if it exceeds a configured maximum retry.
101
88
  */
102
- join(fociPreferred: Transport[], multiSfuFocus?: Transport, onError?: (error: unknown) => void): void;
89
+ join(publishedTransports: Transport[], onError?: (error: unknown) => void): void;
103
90
  /**
104
91
  * Send all necessary events to make this user leave the RTC session.
105
92
  * @param timeout the maximum duration in ms until the promise is forced to resolve.
@@ -16,20 +16,69 @@ limitations under the License.
16
16
 
17
17
  import { type Transport } from "./types.ts";
18
18
 
19
- export interface LivekitTransportConfig extends Transport {
19
+ /**
20
+ * @deprecated Use {@link UnstableLivekitTransport} instead, which has multiple
21
+ * variants to support the migration to newer versions of MSC4195.
22
+ */
23
+ export interface LivekitTransport extends Transport {
20
24
  type: "livekit";
21
25
  livekit_service_url: string;
22
26
  }
23
27
 
24
- export const isLivekitTransportConfig = (object: any): object is LivekitTransportConfig =>
25
- object.type === "livekit" && "livekit_service_url" in object;
28
+ /**
29
+ * @deprecated Use {@link isUnstableLivekitTransport} instead.
30
+ */
31
+ export const isLivekitTransport = (object: unknown): object is LivekitTransport => {
32
+ if (typeof object !== "object" || object === null) return false;
33
+ const transport = object as Transport;
26
34
 
27
- export interface LivekitTransport extends LivekitTransportConfig {
28
- livekit_alias: string;
29
- }
35
+ return transport.type === "livekit" && typeof transport.livekit_service_url === "string";
36
+ };
37
+
38
+ type WebsocketUrl = {
39
+ /**
40
+ * WebSocket URL of the LiveKit server.
41
+ */
42
+ url: string;
43
+ };
30
44
 
31
- export const isLivekitTransport = (object: any): object is LivekitTransport =>
32
- isLivekitTransportConfig(object) && "livekit_alias" in object;
45
+ type ServiceUrl = {
46
+ /**
47
+ * Base URL of the LiveKit JWT service.
48
+ */
49
+ livekit_service_url: string;
50
+ };
51
+
52
+ /**
53
+ * Any LiveKit transport that can be advertised by a homeserver or published by
54
+ * a session member in unstable MSC4195 implementations: `url` only,
55
+ * `livekit_service_url` only, or both during the migration.
56
+ */
57
+ export type UnstableLivekitTransport =
58
+ // Latest MSC4195 variant, with `url`. Indicates that both publishers and
59
+ // subscribers will use the /_matrix/client/v1/rtc/livekit/get_token
60
+ // endpoint.
61
+ | ({ type: "livekit" } & WebsocketUrl)
62
+ // Legacy variant, with `livekit_service_url`. Indicates that both
63
+ // publishers and subscribers will use the endpoints of the provided LiveKit
64
+ // JWT service.
65
+ | ({ type: "livekit" } & ServiceUrl)
66
+ // Transitional variant, with both `url` and `livekit_service_url`.
67
+ // Indicates that both publishers and subscribers may use either the
68
+ // /_matrix/client/v1/rtc/livekit/get_token endpoint or the provided LiveKit
69
+ // JWT service.
70
+ | ({ type: "livekit" } & WebsocketUrl & ServiceUrl);
71
+
72
+ export const isUnstableLivekitTransport = (object: unknown): object is UnstableLivekitTransport => {
73
+ if (typeof object !== "object" || object === null) return false;
74
+ const transport = object as Transport;
75
+
76
+ if (transport.type !== "livekit") return false;
77
+ if (!("url" in transport || "livekit_service_url" in transport)) return false;
78
+ if ("url" in transport && typeof transport.url !== "string") return false;
79
+ if ("livekit_service_url" in transport && typeof transport.livekit_service_url !== "string") return false;
80
+ return true;
81
+ };
33
82
 
34
83
  /**
35
84
  * @deprecated this is just needed for the old focus active / focus fields of a call membership.
@@ -37,7 +86,7 @@ export const isLivekitTransport = (object: any): object is LivekitTransport =>
37
86
  */
38
87
  export interface LivekitFocusSelection extends Transport {
39
88
  type: "livekit";
40
- focus_selection: "oldest_membership" | "multi_sfu";
89
+ focus_selection: "multi_sfu";
41
90
  }
42
91
  /**
43
92
  * @deprecated see LivekitFocusSelection
@@ -33,6 +33,7 @@ import type {
33
33
  Status,
34
34
  IRTCNotificationContent,
35
35
  RTCCallIntent,
36
+ RTCCallCapability,
36
37
  Transport,
37
38
  SlotDescription,
38
39
  RtcSlotEventContent,
@@ -83,7 +84,7 @@ export type MatrixRTCSessionEventHandlerMap = {
83
84
  key: Uint8Array<ArrayBuffer>,
84
85
  encryptionKeyIndex: number,
85
86
  membership: CallMembershipIdentityParts,
86
- rtcBackendIdentity: string,
87
+ backendIdentity: string,
87
88
  ) => void;
88
89
  [MatrixRTCSessionEvent.MembershipManagerError]: (error: unknown) => void;
89
90
  [MatrixRTCSessionEvent.DidSendCallNotification]: (
@@ -104,11 +105,16 @@ export interface SessionConfig {
104
105
  */
105
106
  callIntent?: RTCCallIntent;
106
107
 
108
+ /**
109
+ * What kinds of media this device is capable of handling for the call.
110
+ */
111
+ callCapabilities?: RTCCallCapability[];
112
+
107
113
  /**
108
114
  * Application-specific data to publish in our membership alongside the
109
- * application `type` and `m.call.intent`: in the `application` object of
110
- * an `m.rtc.member` event, or at the top level of a legacy `m.call.member`
111
- * one. Keys should be namespaced. Read back through
115
+ * application `type`, `m.call.intent` and `capabilities`: in the `application`
116
+ * object of an `m.rtc.member` event, or at the top level of a legacy
117
+ * `m.call.member` one. Keys should be namespaced. Read back through
112
118
  * {@link CallMembership.applicationData}.
113
119
  */
114
120
  applicationData?: Record<string, unknown>;
@@ -202,12 +208,6 @@ export interface EncryptionConfig {
202
208
  * media keys for other participants become available.
203
209
  */
204
210
  manageMediaKeys?: boolean;
205
- /**
206
- * The minimum time (in milliseconds) between each attempt to send encryption key(s).
207
- * e.g. if this is set to 1000, then we will send at most one key event every second.
208
- * @deprecated - Not used by the new encryption manager.
209
- */
210
- updateEncryptionKeyThrottle?: number;
211
211
 
212
212
  /**
213
213
  * Sometimes it is necessary to rotate the encryption key after a membership update.
@@ -331,16 +331,6 @@ export class MatrixRTCSession extends TypedEventEmitter<
331
331
  return this.encryptionManager?.isKeyRotationSuppressed ?? false;
332
332
  }
333
333
 
334
- /**
335
- * The callId (sessionId) of the call.
336
- *
337
- * It can be undefined since the callId is only known once the first membership joins.
338
- * The callId is the property that, per definition, groups memberships into one call.
339
- * @deprecated use `slotId` instead.
340
- */
341
- public get callId(): string | undefined {
342
- return this.slotDescription?.id;
343
- }
344
334
  /**
345
335
  * The slotId of the call.
346
336
  * `{application}#{appSpecificId}`
@@ -550,12 +540,12 @@ export class MatrixRTCSession extends TypedEventEmitter<
550
540
  this.initialMembershipCalculated = this.ensureRecalculateSessionMembers();
551
541
  this.setExpiryTimer();
552
542
  }
543
+
553
544
  /*
554
545
  * Returns true if we intend to be participating in the MatrixRTC session.
555
- * This is determined by checking if the relativeExpiry has been set.
556
546
  */
557
547
  public isJoined(): boolean {
558
- return this.membershipManager?.isJoined() ?? false;
548
+ return this.membershipManager?.isActivated() ?? false;
559
549
  }
560
550
 
561
551
  /**
@@ -582,22 +572,15 @@ export class MatrixRTCSession extends TypedEventEmitter<
582
572
  * Announces this user and device as joined to the MatrixRTC session,
583
573
  * and continues to update the membership event to keep it valid until
584
574
  * leaveRoomSession() is called
585
- * This will not subscribe to updates: remember to call subscribe() separately if
586
- * desired.
587
575
  * This method will return immediately and the session will be joined in the background.
588
576
  * @param ownMembershipIdentity the identity of the user and device joining the session.
589
577
  * This will be put into the content.member.
590
- * @param fociPreferred the list of preferred foci to use in the joined RTC membership event.
591
- * If multiSfuFocus is set, this is only needed if this client wants to publish to multiple transports simultaneously.
592
- * @param multiSfuFocus the active focus to use in the joined RTC membership event. Setting this implies the
593
- * membership manager will operate in a multi-SFU connection mode. If `undefined`, an `oldest_membership`
594
- * transport selection will be used instead.
578
+ * @param publishedTransports the list of transports on which the member is publishing.
595
579
  * @param joinConfig - Additional configuration for the joined session.
596
580
  */
597
- public joinRTCSession(
581
+ public join(
598
582
  ownMembershipIdentity: CallMembershipIdentityParts,
599
- fociPreferred: Transport[],
600
- multiSfuFocus?: Transport,
583
+ publishedTransports: Transport[],
601
584
  joinConfig?: JoinSessionConfig,
602
585
  ): void {
603
586
  if (this.isJoined()) {
@@ -632,14 +615,14 @@ export class MatrixRTCSession extends TypedEventEmitter<
632
615
  keyBin: Uint8Array<ArrayBuffer>,
633
616
  encryptionKeyIndex: number,
634
617
  membership: CallMembershipIdentityParts,
635
- rtcBackendIdentity: string,
618
+ backendIdentity: string,
636
619
  ) => {
637
620
  this.emit(
638
621
  MatrixRTCSessionEvent.EncryptionKeyChanged,
639
622
  keyBin,
640
623
  encryptionKeyIndex,
641
624
  membership,
642
- rtcBackendIdentity,
625
+ backendIdentity,
643
626
  );
644
627
  },
645
628
  this.logger,
@@ -650,45 +633,25 @@ export class MatrixRTCSession extends TypedEventEmitter<
650
633
  this.pendingNotificationToSend = this.joinConfig?.notificationType;
651
634
 
652
635
  // Join!
653
- this.membershipManager.join(fociPreferred, multiSfuFocus, (e) => {
636
+ this.membershipManager.join(publishedTransports, (e) => {
654
637
  this.logger.error("MembershipManager encountered an unrecoverable error: ", e);
655
638
  this.emit(MatrixRTCSessionEvent.MembershipManagerError, e);
656
639
  this.emit(MatrixRTCSessionEvent.JoinStateChanged, this.isJoined());
657
640
  });
658
- this.encryptionManager.join(joinConfig);
641
+ this.encryptionManager.join(joinConfig, publishedTransports);
659
642
 
660
643
  this.emit(MatrixRTCSessionEvent.JoinStateChanged, true);
661
644
  }
662
645
 
663
- /**
664
- *
665
- * @param fociPreferred
666
- * @param multiSfuFocus
667
- * @param joinConfig
668
- * @deprecated use the joinRTCSession method instead
669
- */
670
- public joinRoomSession(
671
- fociPreferred: Transport[],
672
- multiSfuFocus?: Transport,
673
- joinConfig?: JoinSessionConfig,
674
- ): void {
675
- const [userId, deviceId] = [this.client.getUserId()!, this.client.getDeviceId()!];
676
- // TODO this wants to become a UUID
677
- const memberId = `${userId}:${deviceId}`;
678
- this.joinRTCSession({ userId, deviceId, memberId }, fociPreferred, multiSfuFocus, joinConfig);
679
- }
680
-
681
646
  /**
682
647
  * Announces this user and device as having left the MatrixRTC session
683
648
  * and stops scheduled updates.
684
- * This will not unsubscribe from updates: remember to call unsubscribe() separately if
685
- * desired.
686
649
  * The membership update required to leave the session will retry if it fails.
687
650
  * Without network connection the promise will never resolve.
688
651
  * A timeout can be provided so that there is a guarantee for the promise to resolve.
689
652
  * @returns Whether the membership update was attempted and did not time out.
690
653
  */
691
- public async leaveRoomSession(timeout: number | undefined = undefined): Promise<boolean> {
654
+ public async leave(timeout?: number): Promise<boolean> {
692
655
  if (!this.isJoined()) {
693
656
  this.logger.info(`Not joined to session in room ${this.roomSubset.roomId}: ignoring leave call`);
694
657
  return false;
@@ -703,19 +666,6 @@ export class MatrixRTCSession extends TypedEventEmitter<
703
666
 
704
667
  return await leavePromise;
705
668
  }
706
- /**
707
- * This returns the focus in use by the oldest membership.
708
- * Do not use since this might be just the focus for the oldest membership. others might use a different focus.
709
- * @deprecated use `member.getTransport(session.getOldestMembership())` instead for the specific member you want to get the focus for.
710
- */
711
- public getFocusInUse(): Transport | undefined {
712
- const oldestMembership = this.getOldestMembership();
713
- return oldestMembership?.getTransport(oldestMembership);
714
- }
715
-
716
- public getOldestMembership(): CallMembership | undefined {
717
- return this.memberships[0];
718
- }
719
669
 
720
670
  /**
721
671
  * Get the call intent for the current call, based on what members are advertising. If one or more
@@ -767,7 +717,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
767
717
  keyInfo.key,
768
718
  keyInfo.keyIndex,
769
719
  keyInfo.membership,
770
- keyInfo.rtcBackendIdentity,
720
+ keyInfo.backendIdentity,
771
721
  );
772
722
  });
773
723
  });
@@ -898,15 +848,6 @@ export class MatrixRTCSession extends TypedEventEmitter<
898
848
  }
899
849
  };
900
850
 
901
- /**
902
- * Call this when something changed that may impacts the current MatrixRTC members in this session.
903
- *
904
- * @deprecated use {@link ensureRecalculateSessionMembers} instead.
905
- */
906
- public _onRTCSessionMemberUpdate = async (): Promise<void> => {
907
- await this.ensureRecalculateSessionMembers();
908
- };
909
-
910
851
  // Recalculations are chained onto this promise, so they never run in parallel.
911
852
  private recalculateSessionMembersPromise: Promise<void> = Promise.resolve();
912
853
 
@@ -15,7 +15,7 @@ limitations under the License.
15
15
  */
16
16
  import { AbortError } from "p-retry";
17
17
 
18
- import { EventType, RelationType } from "../@types/event.ts";
18
+ import { EventType } from "../@types/event.ts";
19
19
  import { type ISendEventResponse, type SendDelayedEventResponse } from "../@types/requests.ts";
20
20
  import { type EmptyObject } from "../@types/common.ts";
21
21
  import type { MatrixClient } from "../client.ts";
@@ -23,7 +23,14 @@ import { ConnectionError, HTTPError, MatrixError } from "../http-api/errors.ts";
23
23
  import { type Logger, logger as rootLogger } from "../logger.ts";
24
24
  import { type Room } from "../models/room.ts";
25
25
  import { type CallMembership, DEFAULT_EXPIRE_DURATION } from "./CallMembership.ts";
26
- import { type Transport, isMyMembership, type RTCCallIntent, Status, type SlotDescription } from "./types.ts";
26
+ import {
27
+ type Transport,
28
+ isMyMembership,
29
+ type RTCCallCapability,
30
+ type RTCCallIntent,
31
+ Status,
32
+ type SlotDescription,
33
+ } from "./types.ts";
27
34
  import { type MembershipConfig, type SessionConfig } from "./MatrixRTCSession.ts";
28
35
  import { type Action, ActionScheduler, type ActionUpdate } from "./MembershipManagerActionScheduler.ts";
29
36
  import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
@@ -36,7 +43,6 @@ import {
36
43
  import { type RtcMembershipData, type SessionMembershipData } from "./membershipData/index.ts";
37
44
  import { computeSlotId } from "./utils.ts";
38
45
  import { deepCompare } from "../utils.ts";
39
- import { isLivekitTransportConfig } from "./LivekitTransport.ts";
40
46
 
41
47
  /* MembershipActionTypes:
42
48
  On Join: ───────────────────┐ ┌───────────────(1)───────────┐
@@ -209,6 +215,7 @@ export class MembershipManager
209
215
  private activated = false;
210
216
  private readonly logger: Logger;
211
217
  protected callIntent: RTCCallIntent | undefined;
218
+ protected callCapabilities: RTCCallCapability[] | undefined;
212
219
  protected applicationData: Record<string, unknown> | undefined;
213
220
 
214
221
  public isActivated(): boolean {
@@ -222,23 +229,18 @@ export class MembershipManager
222
229
  /**
223
230
  * Puts the MembershipManager in a state where it tries to be joined.
224
231
  * It will send delayed events and membership events
225
- * @param fociPreferred the list of preferred foci to use in the joined RTC membership event.
226
- * If multiSfuFocus is set, this is only needed if this client wants to publish to multiple transports simultaneously.
227
- * @param multiSfuFocus the active focus to use in the joined RTC membership event. Setting this implies the
228
- * membership manager will operate in a multi-SFU connection mode. If `undefined`, an `oldest_membership`
229
- * transport selection will be used instead.
232
+ * @param publishedTransports the list of transports on which the member is publishing.
230
233
  * @param onError This will be called once the membership manager encounters an unrecoverable error.
231
234
  * This should bubble up the the frontend to communicate that the call does not work in the current environment.
232
235
  * The original underlying error is preserved as `error.cause`, so consumers can `instanceof`-check the typed
233
236
  * cause.
234
237
  */
235
- public join(fociPreferred: Transport[], multiSfuFocus?: Transport, onError?: (error: unknown) => void): void {
238
+ public join(publishedTransports: Transport[], onError?: (error: unknown) => void): void {
236
239
  if (this.scheduler.running) {
237
240
  this.logger.error("MembershipManager is already running. Ignoring join request.");
238
241
  return;
239
242
  }
240
- this.fociPreferred = fociPreferred;
241
- this.rtcTransport = multiSfuFocus;
243
+ this.publishedTransports = publishedTransports;
242
244
  this.leavePromiseResolvers = undefined;
243
245
  this.activated = true;
244
246
  this.oldStatus = this.status;
@@ -367,6 +369,7 @@ export class MembershipManager
367
369
  this.stateKey = this.makeMembershipStateKey(userId, deviceId);
368
370
  this.state = MembershipManager.defaultState;
369
371
  this.callIntent = joinConfig?.callIntent;
372
+ this.callCapabilities = joinConfig?.callCapabilities;
370
373
  this.applicationData = joinConfig?.applicationData;
371
374
  this.scheduler = new ActionScheduler((type): Promise<ActionUpdate> => {
372
375
  if (this.oldStatus) {
@@ -414,9 +417,7 @@ export class MembershipManager
414
417
  protected deviceId: string;
415
418
  protected userId: string;
416
419
  protected stateKey: string;
417
- protected rtcTransport?: Transport;
418
- /** @deprecated This will be removed in favor or rtcTransport becoming a list of actively used transports */
419
- private fociPreferred?: Transport[];
420
+ protected publishedTransports: Transport[] = [];
420
421
 
421
422
  // Config:
422
423
  private delayedLeaveEventDelayMsOverride?: number;
@@ -753,6 +754,9 @@ export class MembershipManager
753
754
  this.state.expireUpdateIterations = 1;
754
755
  this.state.hasMemberStateEvent = true;
755
756
  this.resetRateLimitCounter(MembershipActionType.SendJoinEvent);
757
+ // A successful (re-)join is a fresh membership: failures accumulated by the previous one
758
+ // (e.g. delayed event restarts that timed out before the server sent our leave) must not carry over.
759
+ this.state.networkErrorRetries.clear();
756
760
  // An UpdateExpiry action might be left over from a previous join event.
757
761
  // We can reach sendJoinEvent when the delayed leave event gets send by the HS.
758
762
  // The branch where we might have a leftover UpdateExpiry action is:
@@ -1003,16 +1007,6 @@ export class MembershipManager
1003
1007
  const needsEmptyStringRoomFix =
1004
1008
  this.slotDescription.application === "m.call" && this.slotDescription.id === "ROOM";
1005
1009
 
1006
- const focusObjects: Pick<SessionMembershipData, "foci_preferred" | "focus_active"> =
1007
- this.rtcTransport === undefined
1008
- ? {
1009
- focus_active: { type: "livekit", focus_selection: "oldest_membership" } as const,
1010
- foci_preferred: this.fociPreferred ?? [],
1011
- }
1012
- : {
1013
- focus_active: { type: "livekit", focus_selection: "multi_sfu" } as const,
1014
- foci_preferred: [this.rtcTransport, ...(this.fociPreferred ?? [])],
1015
- };
1016
1010
  return {
1017
1011
  // Legacy memberships have no application object, so the
1018
1012
  // application's data sits at the top level, under the fields
@@ -1030,7 +1024,9 @@ export class MembershipManager
1030
1024
  "membershipID": `${this.userId}:${this.deviceId}`,
1031
1025
  expires,
1032
1026
  "m.call.intent": this.callIntent,
1033
- ...focusObjects,
1027
+ ...(this.callCapabilities !== undefined ? { capabilities: this.callCapabilities } : {}),
1028
+ "focus_active": { type: "livekit", focus_selection: "multi_sfu" } as const,
1029
+ "foci_preferred": this.publishedTransports,
1034
1030
  ...(ownMembership !== undefined ? { created_ts: ownMembership.createdTs() } : undefined),
1035
1031
  };
1036
1032
  }
@@ -1321,30 +1317,17 @@ export class StickyEventMembershipManager extends MembershipManager {
1321
1317
  * @returns Only returns `RtcMembershipData`
1322
1318
  */
1323
1319
  protected makeMyMembership(): RtcMembershipData {
1324
- const ownMembership = this.ownMembership;
1325
-
1326
- const livekitTransport = isLivekitTransportConfig(this.rtcTransport) ? this.rtcTransport : undefined;
1327
- const relationObject = ownMembership?.eventId
1328
- ? { "m.relation": { rel_type: RelationType.Reference, event_id: ownMembership?.eventId } }
1329
- : {};
1330
1320
  return {
1331
1321
  application: {
1332
1322
  ...this.applicationData,
1333
1323
  type: this.slotDescription.application,
1334
1324
  ...(this.callIntent ? { "m.call.intent": this.callIntent } : {}),
1325
+ ...(this.callCapabilities !== undefined ? { capabilities: this.callCapabilities } : {}),
1335
1326
  },
1336
1327
  slot_id: computeSlotId(this.slotDescription),
1337
- transports: {
1338
- // Make sure we do not add the alias to the transport.
1339
- // It is not needed in matrix2.0. The additional session information will be used to find the right alias on the sfu.
1340
- published: livekitTransport
1341
- ? [{ type: livekitTransport.type, livekit_service_url: livekitTransport.livekit_service_url }]
1342
- : [],
1343
- can_subscribe: ["livekit"],
1344
- },
1328
+ transports: { published: this.publishedTransports, can_subscribe: ["livekit"] },
1345
1329
  member: { device_id: this.deviceId, user_id: this.userId, id: this.memberId },
1346
1330
  versions: [],
1347
- ...relationObject,
1348
1331
  };
1349
1332
  }
1350
1333
  }