Skip to content

Commit 5af046f

Browse files
authored
Use membershipID for session events (#5105)
* User membershipID for session events * fix tests
1 parent f97a9d9 commit 5af046f

File tree

4 files changed

+54
-12
lines changed

4 files changed

+54
-12
lines changed

spec/unit/matrixrtc/CallMembership.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ describe("CallMembership", () => {
170170
expect(membership.scope).toBe("m.room");
171171
});
172172
it("returns correct membershipID", () => {
173-
expect(membership.membershipID).toBe("0");
173+
expect(membership.membershipID).toBe("@alice:example.org:AAAAAAA");
174174
});
175175
it("returns correct unused fields", () => {
176176
expect(membership.getAbsoluteExpiry()).toBe(DEFAULT_EXPIRE_DURATION);

spec/unit/matrixrtc/MembershipManager.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ describe("MembershipManager", () => {
143143
device_id: "AAAAAAA",
144144
expires: 14400000,
145145
foci_preferred: [focus],
146+
membershipID: "@alice:example.org:AAAAAAA",
146147
focus_active: focusActive,
147148
scope: "m.room",
148149
},
@@ -263,6 +264,7 @@ describe("MembershipManager", () => {
263264
expires: 14400000,
264265
device_id: "AAAAAAA",
265266
foci_preferred: [focus],
267+
membershipID: "@alice:example.org:AAAAAAA",
266268
focus_active: focusActive,
267269
} satisfies SessionMembershipData,
268270
userStateKey,
@@ -383,6 +385,7 @@ describe("MembershipManager", () => {
383385
device_id: "AAAAAAA",
384386
expires: 1234567,
385387
foci_preferred: [focus],
388+
membershipID: "@alice:example.org:AAAAAAA",
386389
focus_active: {
387390
focus_selection: "oldest_membership",
388391
type: "livekit",

src/matrixrtc/CallMembership.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,16 @@ import { logger } from "../logger.ts";
3131
export const DEFAULT_EXPIRE_DURATION = 1000 * 60 * 60 * 4;
3232

3333
type CallScope = "m.room" | "m.user";
34-
type Member = { user_id: string; device_id: string; id: string };
34+
type Member = {
35+
user_id: string;
36+
device_id: string;
37+
/**
38+
* The id used on the media backend.
39+
* (With livekit this is the participant identity on the LK SFU)
40+
* This can be a UUID but right now it is `${this.matrixEventData.sender}:${data.device_id}`.
41+
*/
42+
id: string;
43+
};
3544

3645
export interface RtcMembershipData {
3746
"slot_id": string;
@@ -199,6 +208,15 @@ export type SessionMembershipData = {
199208
* The sticky key in case of a sticky event. This string encodes the application + device_id indicating the used slot + device.
200209
*/
201210
"msc4354_sticky_key"?: string;
211+
212+
/**
213+
* The id used on the media backend.
214+
* (With livekit this is the participant identity on the LK SFU)
215+
* This can be a UUID but right now it is `${this.matrixEventData.sender}:${data.device_id}`.
216+
*
217+
* It is compleatly valid to not set this field. Other clients will treat `undefined` as `${this.matrixEventData.sender}:${data.device_id}`
218+
*/
219+
"membershipID"?: string;
202220
};
203221

204222
const checkSessionsMembershipData = (data: IContent, errors: string[]): data is SessionMembershipData => {
@@ -378,7 +396,18 @@ export class CallMembership {
378396
return data.scope;
379397
}
380398
}
381-
399+
/**
400+
* This computes the membership ID for the membership.
401+
* for the sticky event based rtcSessionData this is trivial it is `member.id`.
402+
*
403+
* For the legacy sessionMemberEvents it is a bit more complex. Here we sometimes do not have this data
404+
* in the event content and we expected the SFU and the client to use `${this.matrixEventData.sender}:${data.device_id}`.
405+
*
406+
* So if there is no membershipID we use the hard coded jwt id default (`${this.matrixEventData.sender}:${data.device_id}`)
407+
* value (used until version 0.16.0)
408+
*
409+
* It is also possible for a session event to set a custom membershipID. in that case this will be used.
410+
*/
382411
public get membershipID(): string {
383412
// the createdTs behaves equivalent to the membershipID.
384413
// we only need the field for the legacy member events where we needed to update them
@@ -389,7 +418,12 @@ export class CallMembership {
389418
return data.member.id;
390419
case "session":
391420
default:
392-
return (this.createdTs() ?? "").toString();
421+
return (
422+
// best case we have a client already publishing the right custom membershipId
423+
data.membershipID ??
424+
// alternativly we use the hard coded jwt id defuatl value (used until version 0.16.0)
425+
`${this.matrixEventData.sender}:${data.device_id}`
426+
);
393427
}
394428
}
395429

src/matrixrtc/MembershipManager.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -276,13 +276,8 @@ export class MembershipManager
276276
if (!this.isActivated()) {
277277
return Promise.resolve();
278278
}
279-
const userId = this.client.getUserId();
280-
const deviceId = this.client.getDeviceId();
281-
if (!userId || !deviceId) {
282-
this.logger.error("MembershipManager.onRTCSessionMemberUpdate called without user or device id");
283-
return Promise.resolve();
284-
}
285-
this._ownMembership = memberships.find((m) => isMyMembership(m, userId, deviceId));
279+
280+
this._ownMembership = memberships.find((m) => isMyMembership(m, this.userId, this.deviceId));
286281

287282
if (!this._ownMembership) {
288283
// If one of these actions are scheduled or are getting inserted in the next iteration, we should already
@@ -338,6 +333,7 @@ export class MembershipManager
338333
if (userId === null) throw Error("Missing userId in client");
339334
if (deviceId === null) throw Error("Missing deviceId in client");
340335
this.deviceId = deviceId;
336+
this.userId = userId;
341337
// this needs to become a uuid so that consecutive join/leaves result in a key rotation.
342338
// we keep it as a string for now for backwards compatibility.
343339
this.memberId = this.makeMembershipStateKey(userId, deviceId);
@@ -386,6 +382,7 @@ export class MembershipManager
386382
}
387383
// Membership Event static parameters:
388384
protected deviceId: string;
385+
protected userId: string;
389386
protected memberId: string;
390387
protected rtcTransport?: Transport;
391388
/** @deprecated This will be removed in favor or rtcTransport becoming a list of actively used transports */
@@ -763,6 +760,10 @@ export class MembershipManager
763760
}
764761

765762
// HELPERS
763+
/**
764+
* this creates `${localUserId}_${localDeviceId}_${this.slotDescription.application}${this.slotDescription.id}`
765+
* which is not compatible with membershipID of session type member events. They have to be `${localUserId}:${localDeviceId}`
766+
*/
766767
private makeMembershipStateKey(localUserId: string, localDeviceId: string): string {
767768
const stateKey = `${localUserId}_${localDeviceId}_${this.slotDescription.application}${this.slotDescription.id}`;
768769
if (/^org\.matrix\.msc(3757|3779)\b/.exec(this.room.getVersion())) {
@@ -793,6 +794,10 @@ export class MembershipManager
793794
"call_id": this.slotDescription.id,
794795
"scope": "m.room",
795796
"device_id": this.deviceId,
797+
// DO NOT use this.memberId here since that is the state key (using application...)
798+
// But for session events we use the colon seperated userId and deviceId. The SFU will automatically
799+
// assign those values to the media participant for those versions.
800+
"membershipID": `${this.userId}:${this.deviceId}`,
796801
expires,
797802
"m.call.intent": this.callIntent,
798803
...focusObjects,
@@ -1083,7 +1088,7 @@ export class StickyEventMembershipManager extends MembershipManager {
10831088
},
10841089
slot_id: slotDescriptionToId(this.slotDescription),
10851090
rtc_transports: this.rtcTransport ? [this.rtcTransport] : [],
1086-
member: { device_id: this.deviceId, user_id: this.client.getUserId()!, id: this.memberId },
1091+
member: { device_id: this.deviceId, user_id: this.userId, id: this.memberId },
10871092
versions: [],
10881093
...relationObject,
10891094
};

0 commit comments

Comments
 (0)