@@ -27,7 +27,7 @@ import { KnownMembership } from "../@types/membership.ts";
27
27
import { MembershipManager } from "./MembershipManager.ts" ;
28
28
import { EncryptionManager , type IEncryptionManager } from "./EncryptionManager.ts" ;
29
29
import { logDurationSync } from "../utils.ts" ;
30
- import { type Statistics } from "./types.ts" ;
30
+ import { type Statistics , type CallNotifyType , isMyMembership } from "./types.ts" ;
31
31
import { RoomKeyTransport } from "./RoomKeyTransport.ts" ;
32
32
import type { IMembershipManager } from "./IMembershipManager.ts" ;
33
33
import { RTCEncryptionManager } from "./RTCEncryptionManager.ts" ;
@@ -65,6 +65,15 @@ export type MatrixRTCSessionEventHandlerMap = {
65
65
) => void ;
66
66
[ MatrixRTCSessionEvent . MembershipManagerError ] : ( error : unknown ) => void ;
67
67
} ;
68
+
69
+ export interface SessionConfig {
70
+ /**
71
+ * What kind of notification to send when starting the session.
72
+ * @default `undefined` (no notification)
73
+ */
74
+ notifyType ?: CallNotifyType ;
75
+ }
76
+
68
77
// The names follow these principles:
69
78
// - we use the technical term delay if the option is related to delayed events.
70
79
// - we use delayedLeaveEvent if the option is related to the delayed leave event.
@@ -168,7 +177,7 @@ export interface EncryptionConfig {
168
177
*/
169
178
useKeyDelay ?: number ;
170
179
}
171
- export type JoinSessionConfig = MembershipConfig & EncryptionConfig ;
180
+ export type JoinSessionConfig = SessionConfig & MembershipConfig & EncryptionConfig ;
172
181
173
182
/**
174
183
* A MatrixRTCSession manages the membership & properties of a MatrixRTC session.
@@ -182,7 +191,15 @@ export class MatrixRTCSession extends TypedEventEmitter<
182
191
private encryptionManager ?: IEncryptionManager ;
183
192
// The session Id of the call, this is the call_id of the call Member event.
184
193
private _callId : string | undefined ;
194
+ private joinConfig ?: SessionConfig ;
185
195
private logger : Logger ;
196
+
197
+ /**
198
+ * Whether we're trying to join the session but still waiting for room state
199
+ * to reflect our own membership.
200
+ */
201
+ private joining = false ;
202
+
186
203
/**
187
204
* This timeout is responsible to track any expiration. We need to know when we have to start
188
205
* to ignore other call members. There is no callback for this. This timeout will always be configured to
@@ -447,6 +464,11 @@ export class MatrixRTCSession extends TypedEventEmitter<
447
464
}
448
465
}
449
466
467
+ this . joinConfig = joinConfig ;
468
+ const userId = this . client . getUserId ( ) ! ;
469
+ const deviceId = this . client . getDeviceId ( ) ! ;
470
+ this . joining = ! this . memberships . some ( ( m ) => isMyMembership ( m , userId , deviceId ) ) ;
471
+
450
472
// Join!
451
473
this . membershipManager ! . join ( fociPreferred , fociActive , ( e ) => {
452
474
this . logger . error ( "MembershipManager encountered an unrecoverable error: " , e ) ;
@@ -476,11 +498,11 @@ export class MatrixRTCSession extends TypedEventEmitter<
476
498
477
499
this . logger . info ( `Leaving call session in room ${ this . roomSubset . roomId } ` ) ;
478
500
501
+ this . joining = false ;
479
502
this . encryptionManager ! . leave ( ) ;
480
-
481
503
const leavePromise = this . membershipManager ! . leave ( timeout ) ;
482
- this . emit ( MatrixRTCSessionEvent . JoinStateChanged , false ) ;
483
504
505
+ this . emit ( MatrixRTCSessionEvent . JoinStateChanged , false ) ;
484
506
return await leavePromise ;
485
507
}
486
508
@@ -547,6 +569,22 @@ export class MatrixRTCSession extends TypedEventEmitter<
547
569
}
548
570
}
549
571
572
+ /**
573
+ * Sends a notification corresponding to the configured notify type.
574
+ */
575
+ private sendCallNotify ( ) : void {
576
+ if ( this . joinConfig ?. notifyType !== undefined ) {
577
+ this . client
578
+ . sendEvent ( this . roomSubset . roomId , EventType . CallNotify , {
579
+ "application" : "m.call" ,
580
+ "m.mentions" : { user_ids : [ ] , room : true } ,
581
+ "notify_type" : this . joinConfig . notifyType ,
582
+ "call_id" : this . callId ! ,
583
+ } )
584
+ . catch ( ( e ) => this . logger . error ( "Failed to send call notification" , e ) ) ;
585
+ }
586
+ }
587
+
550
588
/**
551
589
* Call this when the Matrix room members have changed.
552
590
*/
@@ -587,6 +625,15 @@ export class MatrixRTCSession extends TypedEventEmitter<
587
625
} ) ;
588
626
589
627
void this . membershipManager ?. onRTCSessionMemberUpdate ( this . memberships ) ;
628
+
629
+ const userId = this . client . getUserId ( ) ! ;
630
+ const deviceId = this . client . getDeviceId ( ) ! ;
631
+ if ( this . joining && this . memberships . some ( ( m ) => isMyMembership ( m , userId , deviceId ) ) ) {
632
+ this . joining = false ;
633
+ // If we're the first member in the call, we're responsible for
634
+ // sending the notification event
635
+ if ( oldMemberships . length === 0 ) this . sendCallNotify ( ) ;
636
+ }
590
637
}
591
638
// This also needs to be done if `changed` = false
592
639
// A member might have updated their fingerprint (created_ts)
0 commit comments