diff --git a/src/rtcSessionHelpers.ts b/src/rtcSessionHelpers.ts index e4176dc0..ba467426 100644 --- a/src/rtcSessionHelpers.ts +++ b/src/rtcSessionHelpers.ts @@ -18,8 +18,9 @@ import { AutoDiscovery } from "matrix-js-sdk/lib/autodiscovery"; import { PosthogAnalytics } from "./analytics/PosthogAnalytics"; import { Config } from "./config/Config"; import { ElementWidgetActions, widget, type WidgetHelpers } from "./widget"; -import { MatrixRTCFocusMissingError } from "./utils/errors.ts"; -import { getUrlParams } from "./UrlParams.ts"; +import { MatrixRTCFocusMissingError } from "./utils/errors"; +import { getUrlParams } from "./UrlParams"; +import { getJoinedNonFunctionalMembers } from "./utils/matrix"; const FOCI_WK_KEY = "org.matrix.msc4143.rtc_foci"; @@ -94,6 +95,12 @@ async function makePreferredLivekitFoci( // if (focusOtherMembers) preferredFoci.push(focusOtherMembers); } +function getNotifyType(room: Room): CallNotifyType | undefined { + if (room.isCallRoom()) return undefined; + if (getJoinedNonFunctionalMembers(room).length === 2) return "ring"; + return "notify"; +} + export async function enterRTCSession( rtcSession: MatrixRTCSession, encryptMedia: boolean, @@ -116,6 +123,7 @@ export async function enterRTCSession( await makePreferredLivekitFoci(rtcSession, livekitAlias), makeActiveFocus(), { + notifyType: getNotifyType(rtcSession.room), useNewMembershipManager, manageMediaKeys: encryptMedia, ...(useDeviceSessionMemberEvents !== undefined && { diff --git a/src/utils/matrix.ts b/src/utils/matrix.ts index 0a2b5c1a..2f9e2ce1 100644 --- a/src/utils/matrix.ts +++ b/src/utils/matrix.ts @@ -12,7 +12,10 @@ import { IndexedDBStore, MemoryStore, Preset, + type RoomMember, + UNSTABLE_ELEMENT_FUNCTIONAL_USERS, Visibility, + Direction, } from "matrix-js-sdk"; import { type ISyncStateData, type SyncState } from "matrix-js-sdk/lib/sync"; import { logger } from "matrix-js-sdk/lib/logger"; @@ -336,6 +339,27 @@ export function getRelativeRoomUrl( return `/room/#${roomPart}?${generateUrlSearchParams(roomId, encryptionSystem, viaServers).toString()}`; } +/** + * Returns all room members that are non-functional (all actual room members). + * A functional user is a user that is not a real user, but a bot, assistant, etc. + */ +export function getJoinedNonFunctionalMembers(room: Room): RoomMember[] { + const functionalUsersStateEvent = room + .getLiveTimeline() + .getState(Direction.Forward) + ?.getStateEvents(UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, ""); + + const functionalMembers = Array.isArray( + functionalUsersStateEvent?.getContent().service_members, + ) + ? functionalUsersStateEvent.getContent().service_members + : []; + + return room + .getJoinedMembers() + .filter((m) => !functionalMembers.includes(m.userId)); +} + /** * Perform a network operation with retries on ConnectionError. * If the error is not retryable, or the max number of retries is reached, the error is rethrown.