Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
157 commits
Select commit Hold shift + click to select a range
9011ae4
temp
toger5 Aug 27, 2025
35319dd
Fix some errors in CallViewModel
robintown Aug 27, 2025
d9b6302
Fix crash?
robintown Aug 27, 2025
376a4b4
initial compiling version
toger5 Aug 27, 2025
c6e8c94
Fix makeFocus
robintown Aug 27, 2025
cb91f1a
Make it actually join the session
robintown Aug 27, 2025
7b88420
first video!
toger5 Aug 27, 2025
a10489d
publish audio in remote rooms
toger5 Aug 27, 2025
6bdfd7f
add comment
toger5 Aug 27, 2025
55b46b3
introduce publishingParticipants$
toger5 Aug 27, 2025
8ffb360
add local storage + more readable + remoteParticipants + use publishi…
toger5 Aug 28, 2025
33bc78e
add logging
toger5 Aug 28, 2025
a617a92
make it work
toger5 Aug 28, 2025
e4a54e3
refactor connnection class
toger5 Aug 28, 2025
802ebf8
refactor connection
toger5 Aug 28, 2025
598371b
lots of work. noone knows if it works.
toger5 Aug 28, 2025
02f4c73
Add my own local storage SFU config stuff too
robintown Aug 28, 2025
d46fe55
Import unfinished mute states refactor
robintown Aug 28, 2025
386dc6c
temp before holiday
toger5 Aug 28, 2025
e08f16f
All my Friday work. Demoable!
robintown Aug 29, 2025
c809873
one e2ee worker per session
toger5 Sep 15, 2025
cc870c3
enable encryption in per sender case
toger5 Sep 16, 2025
38d78dd
make audio work
toger5 Sep 16, 2025
ccfd32c
move leave logic into view model
toger5 Sep 16, 2025
41e152f
dont throw disconnected error at start of the call
toger5 Sep 17, 2025
d9fe310
start fixing CallViewModel tests.
toger5 Sep 19, 2025
02f23e2
remove todo from matrix audio renderer
toger5 Sep 22, 2025
dddda70
add todo comments and who works on them
toger5 Sep 22, 2025
8bf2489
TODO: settings modal with multiple connections
toger5 Sep 22, 2025
78e9521
Make track processor work
toger5 Sep 23, 2025
7777179
cleanup (delete files useLivekit) now covered by Connection.ts
toger5 Sep 23, 2025
96e96a5
fix leaving
toger5 Sep 23, 2025
6b44f3b
a tiny bit of tests lint fixes.
toger5 Sep 23, 2025
8e21ea6
Merge branch 'livekit' into voip-team/rebased-multiSFU
robintown Sep 24, 2025
f99a256
Reset matrix-js-sdk to multi SFU branch
robintown Sep 24, 2025
edd3eb8
Implement screen sharing
robintown Sep 24, 2025
6cf0207
Make UI react instantly to hanging up but also wait for leave sound
robintown Sep 25, 2025
530fbaf
Clear up the room membership confusion around reading session members
robintown Sep 25, 2025
4980d8a
Merge branch 'livekit' into voip-team/rebased-multiSFU
robintown Sep 25, 2025
0759f9b
Don't render audio from participants that aren't meant to be publishing
robintown Sep 26, 2025
dbdf853
Stop connections on view model destroy
robintown Sep 26, 2025
a4a0a58
Remove the option to show non-member ("ghost") participants
robintown Sep 26, 2025
edf68d1
refactoring: prep work extract to file + documentation
BillCarsonFr Sep 30, 2025
2819c79
use updated multi sfu js-sdk
toger5 Sep 30, 2025
b00f7d5
refactor: Remote / Publish Connection and constructor
BillCarsonFr Sep 30, 2025
71127a4
Merge pull request #3516 from element-hq/toger5/voip-team/rebased-mul…
robintown Sep 30, 2025
879a1d4
Connection: add Connection state and handle error on start
BillCarsonFr Oct 1, 2025
3d8639d
Connection states tests
BillCarsonFr Oct 1, 2025
47c876f
lint fixes
BillCarsonFr Oct 1, 2025
2290016
extract common test setup
BillCarsonFr Oct 1, 2025
6a1f7dd
ConnectionState: test livekit connection states
BillCarsonFr Oct 1, 2025
e8bf817
tests: end scope tests
BillCarsonFr Oct 1, 2025
dfaa6a3
fix lint errors
BillCarsonFr Oct 1, 2025
68aae4a
fix another rename + another js-sdk bump
toger5 Oct 2, 2025
0502f66
tests: Add publisher observable tests
BillCarsonFr Oct 2, 2025
84f95be
test: Ensure scope for publishers observer
BillCarsonFr Oct 2, 2025
00401ca
refactor: PublishConnection extract from giant constructor
BillCarsonFr Oct 2, 2025
86fb026
Turn multi-SFU media transport into a developer option
robintown Oct 3, 2025
1820cac
Create media items for session members not joined to LiveKit
robintown Oct 3, 2025
1fff71a
Actually leave the MatrixRTC session again
robintown Oct 4, 2025
91a366f
tests: Publish connection states
BillCarsonFr Oct 6, 2025
597e678
Merge branch 'voip-team/rebased-multiSFU' into valere/multi-sfu/conne…
BillCarsonFr Oct 7, 2025
c3c0516
Lint: fix all the lint errors
BillCarsonFr Oct 7, 2025
c820ba3
build: update lock file
BillCarsonFr Oct 7, 2025
7437961
lint: fix import order
BillCarsonFr Oct 7, 2025
529cb8a
prettier !
BillCarsonFr Oct 7, 2025
18ba02c
knip: remove dead code
BillCarsonFr Oct 7, 2025
05e7b5a
fixup MediaView tests
BillCarsonFr Oct 7, 2025
669bc76
Replace calls to deprecated resolveActiveFocus
robintown Oct 8, 2025
13fb466
test: Fix mediaView test, ,member is not optional anymore
BillCarsonFr Oct 8, 2025
f5ea734
esLint fix
BillCarsonFr Oct 8, 2025
afe004c
Remove un-necessary transport field, already accessible from connection
BillCarsonFr Oct 8, 2025
427a8dd
test: Fix Audio render tests and added more
BillCarsonFr Oct 8, 2025
1a4b38c
Document ObservableScope.reconcile
robintown Oct 8, 2025
e346c8c
Re-enable React strict mode
robintown Oct 8, 2025
c96e81b
Simplify type of audio participants exposed from CallViewModel
robintown Oct 8, 2025
5da780e
Remove dead MuteStates file
robintown Oct 8, 2025
b1d1437
Add comments to Async
robintown Oct 8, 2025
e884744
Correct / document some missing bits in tests
robintown Oct 8, 2025
8778be8
Fix doc comment typo
robintown Oct 8, 2025
3691e71
Restore a hidden 'null' state for the local transport/connection
robintown Oct 8, 2025
dee06a4
Remove unused useIsEarpiece hook
robintown Oct 8, 2025
dcc3ab6
Remove MockedObject from mockMediaDevices type signature
robintown Oct 8, 2025
00daf83
Remove local participant case (now enforced by types) from audio tests
robintown Oct 8, 2025
2d7e424
Note a potential resource leak
robintown Oct 8, 2025
5be3b91
Fix focus connection state typo, simplify its initialization
robintown Oct 8, 2025
64c2e59
Update outdated comment
robintown Oct 8, 2025
2c576a7
Clean up subscriptions in Connection tests
robintown Oct 8, 2025
85ffe68
Remove outdated comment
robintown Oct 8, 2025
4c6b960
fix: use correct TestEachFunction
BillCarsonFr Oct 9, 2025
39f8cb9
make compatible with related_event (async CallMembership) branch
toger5 Oct 9, 2025
7cbb1ec
Simplify AudioRenderer and add more tests
BillCarsonFr Oct 9, 2025
a500915
test: Fix mute test, behavior change from setMuted to setAudioEnabled
BillCarsonFr Oct 9, 2025
f9f2896
Merge branch 'voip-team/rebased-multiSFU' of github.com:element-hq/el…
robintown Oct 9, 2025
de5f519
Merge branch 'livekit' into voip-team/rebased-multiSFU
robintown Oct 9, 2025
6710f4c
Test: Fix mocking to fix failing tests
BillCarsonFr Oct 10, 2025
1ab081d
test: MISSING_MATRIX_RTC_FOCUS renamed as MISSING_MATRIX_RTC_TRANSPORT
BillCarsonFr Oct 10, 2025
0fd4143
Merge branch 'livekit' into voip-team/rebased-multiSFU
toger5 Oct 10, 2025
4608d68
Merge branch 'voip-team/rebased-multiSFU' into valere/multi-sfu/conne…
BillCarsonFr Oct 10, 2025
4a8f5bc
post merge lint fixes
BillCarsonFr Oct 10, 2025
1e75f9a
test: fix additional test with proper mutestate fix
BillCarsonFr Oct 10, 2025
cca46bd
Merge branch 'voip-team/rebased-multiSFU' into valere/multi-sfu/conne…
BillCarsonFr Oct 10, 2025
2fc7f11
prettier fix
BillCarsonFr Oct 10, 2025
fc2384e
post merge fixes (js-sdk changes)
BillCarsonFr Oct 10, 2025
c846ea6
Merge pull request #3521 from element-hq/valere/multi-sfu/connection_…
BillCarsonFr Oct 13, 2025
8e6eb70
refactor: use `EnterRTCSessionOptions` instead of unnamed bools
BillCarsonFr Oct 13, 2025
8823be6
refactor extract inner classes to their own files
BillCarsonFr Oct 13, 2025
0e1b61a
refactor: Split out all exports of CallViewModel to their own file
BillCarsonFr Oct 13, 2025
a5aba92
dependency: depends on js-sdk develop
BillCarsonFr Oct 13, 2025
a9db9c8
ErrorHandling: publish connection error handling
BillCarsonFr Oct 14, 2025
60332dc
fix js-sdk dependency format
BillCarsonFr Oct 14, 2025
58d60b3
fix CI failing with Invalid value "iife" for option "worker.format"
BillCarsonFr Oct 14, 2025
93d763f
devtool: quick display of focus URL in stats tile
BillCarsonFr Oct 14, 2025
a18700c
Avoid updating membership during focus switch
robintown Oct 14, 2025
392c51f
Merge branch 'voip-team/rebased-multiSFU' of github.com:element-hq/el…
robintown Oct 14, 2025
b030d30
Fix crash during focus switching
robintown Oct 14, 2025
a6c4fb4
review: count as publishing even if not yet connected to LK
BillCarsonFr Oct 14, 2025
2de7a20
Remove outdated comment
robintown Oct 14, 2025
bcbf7a9
Initialize preferredTransport$ in a less unusual way
robintown Oct 14, 2025
13636b7
Replace deprecated CallMembership.sender with userId
robintown Oct 14, 2025
95069fd
Fix joining call with audio and video muted
robintown Oct 14, 2025
625cfa1
Move sorting bin calculation into UserMedia
robintown Oct 14, 2025
9f4e993
Elaborate on a TODO for preloading JWT tokens
robintown Oct 14, 2025
ea17ed7
Rename 'localTransport' to 'transport', since it's often remote
robintown Oct 14, 2025
2dc6134
Stick to the term 'transport' rather than 'focus'
robintown Oct 14, 2025
b0eb566
Simplify local transport connection state tracking
robintown Oct 14, 2025
102e581
Serialize updates to the call intent
robintown Oct 14, 2025
2c66e11
Fix connection tests
robintown Oct 14, 2025
717c742
Require ObservableScopes of state holders to be specified explicitly
robintown Oct 16, 2025
d5efba2
Fix resource leaks when we stop using a connection
robintown Oct 16, 2025
13894aa
Simplify some test helpers that no longer need continuations
robintown Oct 17, 2025
27f24ca
Document CallViewModel and some terms used
robintown Oct 21, 2025
1b3a564
Document generateKeyed$ more thoroughly
robintown Oct 21, 2025
4936cdf
Merge pull request #3537 from robintown/connection-leaks
robintown Oct 21, 2025
5526cd7
Add sticky event support (#3513)
toger5 Oct 22, 2025
19daf5f
update snapshot (in call view)
toger5 Oct 22, 2025
8da111d
remove option to enable/disable room transport
toger5 Oct 22, 2025
9ca8962
Remove unused useECConnectionState React hook
robintown Oct 22, 2025
a1c7255
Restore CallViewModel tests to working order
robintown Oct 22, 2025
58cd12b
Fix a number of remaining test failures
robintown Oct 23, 2025
2c5afe8
Skip GroupCallView tests for now
robintown Oct 23, 2025
75a8dd2
Remove some dead code
robintown Oct 23, 2025
5245b22
Remove dead test files
robintown Oct 23, 2025
6be7749
Remove even more dead code
robintown Oct 23, 2025
e0b9a85
Merge branch 'livekit' into voip-team/rebased-multiSFU
robintown Oct 23, 2025
db2004f
Remove unused string
robintown Oct 23, 2025
e06f288
update playwright
BillCarsonFr Oct 23, 2025
a638acd
CI: Increase job timeout
BillCarsonFr Oct 23, 2025
348a6fe
test CI changing ports
BillCarsonFr Oct 23, 2025
c572d2e
test CI
BillCarsonFr Oct 23, 2025
185d7d1
CI test
BillCarsonFr Oct 23, 2025
552e121
revert CI test changes
BillCarsonFr Oct 23, 2025
150cdf6
CI try some more logs
BillCarsonFr Oct 23, 2025
0823936
revert CI test changes
BillCarsonFr Oct 23, 2025
d52656c
CI try without USE_DOCKER
BillCarsonFr Oct 23, 2025
918d67b
CI: revert to synapse latest
BillCarsonFr Oct 23, 2025
301cf2f
Revert "CI try without USE_DOCKER"
BillCarsonFr Oct 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
fail_ci_if_error: true
playwright:
name: Run end-to-end tests
timeout-minutes: 30
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
Expand Down
2 changes: 2 additions & 0 deletions backend/dev_homeserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ experimental_features:
# MSC4222 needed for syncv2 state_after. This allow clients to
# correctly track the state of the room.
msc4222_enabled: true
# sticky events for matrixRTC user state
msc4354_enabled: true

# The maximum allowed duration by which sent events can be delayed, as
# per MSC4140. Must be a positive value if set. Defaults to no
Expand Down
12 changes: 7 additions & 5 deletions locales/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,14 @@
"livekit_server_info": "LiveKit Server Info",
"livekit_sfu": "LiveKit SFU: {{url}}",
"matrix_id": "Matrix ID: {{id}}",
"multi_sfu": "Multi-SFU media transport",
"mute_all_audio": "Mute all audio (participants, reactions, join sounds)",
"prefer_sticky_events": {
"description": "Improves reliability of calls (requires homeserver support)",
"label": "Prefer sticky events"
},
"show_connection_stats": "Show connection statistics",
"show_non_member_tiles": "Show tiles for non-member media",
"url_params": "URL parameters",
"use_new_membership_manager": "Use the new implementation of the call MembershipManager",
"use_to_device_key_transport": "Use to device key transport. This will fallback to room key transport when another call member sent a room key"
"url_params": "URL parameters"
},
"disconnected_banner": "Connectivity to the server has been lost.",
"error": {
Expand All @@ -92,7 +94,7 @@
"generic_description": "Submitting debug logs will help us track down the problem.",
"insufficient_capacity": "Insufficient capacity",
"insufficient_capacity_description": "The server has reached its maximum capacity and you cannot join the call at this time. Try again later, or contact your server admin if the problem persists.",
"matrix_rtc_focus_missing": "The server is not configured to work with {{brand}}. Please contact your server admin (Domain: {{domain}}, Error Code: {{ errorCode }}).",
"matrix_rtc_transport_missing": "The server is not configured to work with {{brand}}. Please contact your server admin (Domain: {{domain}}, Error Code: {{ errorCode }}).",
"open_elsewhere": "Opened in another tab",
"open_elsewhere_description": "{{brand}} has been opened in another tab. If that doesn't sound right, try reloading the page.",
"room_creation_restricted": "Failed to create call",
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"@opentelemetry/sdk-trace-base": "^2.0.0",
"@opentelemetry/sdk-trace-web": "^2.0.0",
"@opentelemetry/semantic-conventions": "^1.25.1",
"@playwright/test": "^1.52.0",
"@playwright/test": "^1.56.1",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-visually-hidden": "^1.0.3",
Expand Down Expand Up @@ -99,6 +99,7 @@
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-rxjs": "^5.0.3",
"eslint-plugin-unicorn": "^56.0.0",
"fetch-mock": "11.1.5",
"global-jsdom": "^26.0.0",
"i18next": "^24.0.0",
"i18next-browser-languagedetector": "^8.0.0",
Expand All @@ -108,7 +109,7 @@
"livekit-client": "^2.13.0",
"lodash-es": "^4.17.21",
"loglevel": "^1.9.1",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#head=develop",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#head=toger5/sticky-events&commit=e7f5bec51b6f70501a025b79fe5021c933385b21",
"matrix-widget-api": "^1.13.0",
"normalize.css": "^8.0.1",
"observable-hooks": "^4.2.3",
Expand Down
8 changes: 0 additions & 8 deletions src/MediaDevicesContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,6 @@ export function useMediaDevices(): MediaDevices {
return mediaDevices;
}

export const useIsEarpiece = (): boolean => {
const devices = useMediaDevices();
const audioOutput = useObservableEagerState(devices.audioOutput.selected$);
const available = useObservableEagerState(devices.audioOutput.available$);
if (!audioOutput?.id) return false;
return available.get(audioOutput.id)?.type === "earpiece";
};

/**
* A convenience hook to get the audio node configuration for the earpiece.
* It will check the `useAsEarpiece` of the `audioOutput` device and return
Expand Down
25 changes: 24 additions & 1 deletion src/RTCConnectionStats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,26 @@ import mediaViewStyles from "../src/tile/MediaView.module.css";
interface Props {
audio?: RTCInboundRtpStreamStats | RTCOutboundRtpStreamStats;
video?: RTCInboundRtpStreamStats | RTCOutboundRtpStreamStats;
focusUrl?: string;
}

const extractDomain = (url: string): string => {
try {
const parsedUrl = new URL(url);
return parsedUrl.hostname; // Returns "kdk.cpm"
} catch (error) {
console.error("Invalid URL:", error);
return url;
}
};

// This is only used in developer mode for debugging purposes, so we don't need full localization
export const RTCConnectionStats: FC<Props> = ({ audio, video, ...rest }) => {
export const RTCConnectionStats: FC<Props> = ({
audio,
video,
focusUrl,
...rest
}) => {
const [showModal, setShowModal] = useState(false);
const [modalContents, setModalContents] = useState<
"video" | "audio" | "none"
Expand Down Expand Up @@ -55,6 +71,13 @@ export const RTCConnectionStats: FC<Props> = ({ audio, video, ...rest }) => {
</pre>
</div>
</Modal>
{focusUrl && (
<div>
<Text as="span" size="xs" title="focusURL">
&nbsp;{extractDomain(focusUrl)}
</Text>
</div>
)}
{audio && (
<div>
<Button
Expand Down
9 changes: 5 additions & 4 deletions src/button/ReactionToggleButton.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ Please see LICENSE in the repository root for full details.
*/

import { act, render } from "@testing-library/react";
import { expect, test } from "vitest";
import { expect, test, vi } from "vitest";
import { TooltipProvider } from "@vector-im/compound-web";
import { userEvent } from "@testing-library/user-event";
import { type ReactNode } from "react";
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc";

import { ReactionToggleButton } from "./ReactionToggleButton";
import { ElementCallReactionEventType } from "../reactions";
Expand All @@ -20,7 +19,9 @@ import { alice, local, localRtcMember } from "../utils/test-fixtures";
import { type MockRTCSession } from "../utils/test";
import { ReactionsSenderProvider } from "../reactions/useReactionsSender";

const localIdent = `${localRtcMember.sender}:${localRtcMember.deviceId}`;
vi.mock("livekit-client/e2ee-worker?worker");

const localIdent = `${localRtcMember.userId}:${localRtcMember.deviceId}`;

function TestComponent({
rtcSession,
Expand All @@ -33,7 +34,7 @@ function TestComponent({
<TooltipProvider>
<ReactionsSenderProvider
vm={vm}
rtcSession={rtcSession as unknown as MatrixRTCSession}
rtcSession={rtcSession.asMockedSession()}
>
<ReactionToggleButton vm={vm} identifier={localIdent} />
</ReactionsSenderProvider>
Expand Down
2 changes: 1 addition & 1 deletion src/grid/GridLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import { distinctUntilChanged } from "rxjs";
import { useObservableEagerState } from "observable-hooks";

import { type GridLayout as GridLayoutModel } from "../state/CallViewModel";
import { type GridLayout as GridLayoutModel } from "../state/layout-types.ts";
import styles from "./GridLayout.module.css";
import { useInitial } from "../useInitial";
import { type CallLayout, arrangeTiles } from "./CallLayout";
Expand Down
2 changes: 1 addition & 1 deletion src/grid/OneOnOneLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { type ReactNode, useCallback, useMemo } from "react";
import { useObservableEagerState } from "observable-hooks";
import classNames from "classnames";

import { type OneOnOneLayout as OneOnOneLayoutModel } from "../state/CallViewModel";
import { type OneOnOneLayout as OneOnOneLayoutModel } from "../state/layout-types.ts";
import { type CallLayout, arrangeTiles } from "./CallLayout";
import styles from "./OneOnOneLayout.module.css";
import { type DragCallback, useUpdateLayout } from "./Grid";
Expand Down
2 changes: 1 addition & 1 deletion src/grid/SpotlightExpandedLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.

import { type ReactNode, useCallback } from "react";

import { type SpotlightExpandedLayout as SpotlightExpandedLayoutModel } from "../state/CallViewModel";
import { type SpotlightExpandedLayout as SpotlightExpandedLayoutModel } from "../state/layout-types.ts";
import { type CallLayout } from "./CallLayout";
import { type DragCallback, useUpdateLayout } from "./Grid";
import styles from "./SpotlightExpandedLayout.module.css";
Expand Down
2 changes: 1 addition & 1 deletion src/grid/SpotlightLandscapeLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useObservableEagerState } from "observable-hooks";
import classNames from "classnames";

import { type CallLayout } from "./CallLayout";
import { type SpotlightLandscapeLayout as SpotlightLandscapeLayoutModel } from "../state/CallViewModel";
import { type SpotlightLandscapeLayout as SpotlightLandscapeLayoutModel } from "../state/layout-types.ts";
import styles from "./SpotlightLandscapeLayout.module.css";
import { useUpdateLayout, useVisibleTiles } from "./Grid";

Expand Down
2 changes: 1 addition & 1 deletion src/grid/SpotlightPortraitLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useObservableEagerState } from "observable-hooks";
import classNames from "classnames";

import { type CallLayout, arrangeTiles } from "./CallLayout";
import { type SpotlightPortraitLayout as SpotlightPortraitLayoutModel } from "../state/CallViewModel";
import { type SpotlightPortraitLayout as SpotlightPortraitLayoutModel } from "../state/layout-types.ts";
import styles from "./SpotlightPortraitLayout.module.css";
import { useUpdateLayout, useVisibleTiles } from "./Grid";
import { useBehavior } from "../useBehavior";
Expand Down
50 changes: 40 additions & 10 deletions src/home/useGroupCallRooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,19 +113,49 @@ const roomIsJoinable = (room: Room): boolean => {
}
};

/**
* Determines if a given room has call events in it, and therefore
* is likely to be a call room.
* @param room The Matrix room instance.
* @returns `true` if the room has call events.
*/
const roomHasCallMembershipEvents = (room: Room): boolean => {
switch (room.getMyMembership()) {
case KnownMembership.Join:
return !!room
.getLiveTimeline()
.getState(EventTimeline.FORWARDS)
?.events?.get(EventType.GroupCallMemberPrefix);
case KnownMembership.Knock:
// Assume that a room you've knocked on is able to hold calls
// Check our room membership first, to rule out any rooms
// we can't have a call in.
const myMembership = room.getMyMembership();
if (myMembership === KnownMembership.Knock) {
// Assume that a room you've knocked on is able to hold calls
return true;
} else if (myMembership !== KnownMembership.Join) {
// Otherwise, non-joined rooms should never show up.
return false;
}

// Legacy member state checks (cheaper to check.)
const timeline = room.getLiveTimeline();
if (
timeline
.getState(EventTimeline.FORWARDS)
?.events?.has(EventType.GroupCallMemberPrefix)
) {
return true;
}

// Check for *active* calls using sticky events.
for (const sticky of room._unstable_getStickyEvents()) {
if (sticky.getType() === EventType.RTCMembership) {
return true;
default:
return false;
}
}

// Otherwise, check recent event history to see if anyone had
// sent a call membership in here.
return timeline.getEvents().some(
(e) =>
// Membership events only count if both of these are true
e.unstableStickyInfo && e.getType() === EventType.GroupCallMemberPrefix,
);
// Otherwise, it's *unlikely* this room was ever a call.
};

export function useGroupCallRooms(client: MatrixClient): GroupCallRoom[] {
Expand Down
Loading