Skip to content

Commit b8af9a0

Browse files
authored
Merge pull request #648 from vector-im/dbkr/tiles_for_everyone
Show tiles for members we're trying to connect to
2 parents 97c2946 + 50e9e33 commit b8af9a0

File tree

12 files changed

+89
-63
lines changed

12 files changed

+89
-63
lines changed

public/locales/en-GB/app.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"{{count}} people connected|one": "{{count}} person connected",
33
"{{count}} people connected|other": "{{count}} people connected",
44
"{{displayName}}, your call is now ended": "{{displayName}}, your call is now ended",
5+
"{{name}} (Connecting...)": "{{name}} (Connecting...)",
56
"{{name}} is presenting": "{{name}} is presenting",
67
"{{name}} is talking…": "{{name}} is talking…",
78
"{{names}}, {{name}}": "{{names}}, {{name}}",

src/room/GroupCallView.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ export function GroupCallView({
7676
toggleScreensharing,
7777
requestingScreenshare,
7878
isScreensharing,
79-
localScreenshareFeed,
8079
screenshareFeeds,
8180
participants,
8281
unencryptedEventsFromUsers,
@@ -221,6 +220,7 @@ export function GroupCallView({
221220
client={client}
222221
roomName={groupCall.room.name}
223222
avatarUrl={avatarUrl}
223+
participants={participants}
224224
microphoneMuted={microphoneMuted}
225225
localVideoMuted={localVideoMuted}
226226
toggleLocalVideoMuted={toggleLocalVideoMuted}
@@ -230,7 +230,6 @@ export function GroupCallView({
230230
onLeave={onLeave}
231231
toggleScreensharing={toggleScreensharing}
232232
isScreensharing={isScreensharing}
233-
localScreenshareFeed={localScreenshareFeed}
234233
screenshareFeeds={screenshareFeeds}
235234
roomIdOrAlias={roomIdOrAlias}
236235
unencryptedEventsFromUsers={unencryptedEventsFromUsers}

src/room/InCallView.tsx

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
7070
interface Props {
7171
client: MatrixClient;
7272
groupCall: GroupCall;
73+
participants: RoomMember[];
7374
roomName: string;
7475
avatarUrl: string;
7576
microphoneMuted: boolean;
@@ -82,14 +83,16 @@ interface Props {
8283
onLeave: () => void;
8384
isScreensharing: boolean;
8485
screenshareFeeds: CallFeed[];
85-
localScreenshareFeed: CallFeed;
8686
roomIdOrAlias: string;
8787
unencryptedEventsFromUsers: Set<string>;
8888
hideHeader: boolean;
8989
}
9090

91-
export interface Participant {
91+
// Represents something that should get a tile on the layout,
92+
// ie. a user's video feed or a screen share feed.
93+
export interface TileDescriptor {
9294
id: string;
95+
member: RoomMember;
9396
focused: boolean;
9497
presenter: boolean;
9598
callFeed?: CallFeed;
@@ -99,6 +102,7 @@ export interface Participant {
99102
export function InCallView({
100103
client,
101104
groupCall,
105+
participants,
102106
roomName,
103107
avatarUrl,
104108
microphoneMuted,
@@ -111,7 +115,6 @@ export function InCallView({
111115
toggleScreensharing,
112116
isScreensharing,
113117
screenshareFeeds,
114-
localScreenshareFeed,
115118
roomIdOrAlias,
116119
unencryptedEventsFromUsers,
117120
hideHeader,
@@ -185,39 +188,48 @@ export function InCallView({
185188
}, [setLayout]);
186189

187190
const items = useMemo(() => {
188-
const participants: Participant[] = [];
189-
190-
for (const callFeed of userMediaFeeds) {
191-
participants.push({
192-
id: callFeed.stream.id,
193-
callFeed,
194-
focused:
195-
screenshareFeeds.length === 0 && callFeed.userId === activeSpeaker,
196-
isLocal: callFeed.isLocal(),
191+
const tileDescriptors: TileDescriptor[] = [];
192+
193+
// one tile for each participants, to start with (we want a tile for everyone we
194+
// think should be in the call, even if we don't have a media feed for them yet)
195+
for (const p of participants) {
196+
const userMediaFeed = userMediaFeeds.find((f) => f.userId === p.userId);
197+
198+
// NB. this assumes that the same user can't join more than once from multiple
199+
// devices, but the participants are just RoomMembers, so this assumption is baked
200+
// into GroupCall itself.
201+
tileDescriptors.push({
202+
id: p.userId,
203+
member: p,
204+
callFeed: userMediaFeed,
205+
focused: screenshareFeeds.length === 0 && p.userId === activeSpeaker,
206+
isLocal: p.userId === client.getUserId(),
197207
presenter: false,
198208
});
199209
}
200210

201-
for (const callFeed of screenshareFeeds) {
202-
const userMediaItem = participants.find(
203-
(item) => item.callFeed.userId === callFeed.userId
211+
// add the screenshares too
212+
for (const screenshareFeed of screenshareFeeds) {
213+
const userMediaItem = tileDescriptors.find(
214+
(item) => item.member.userId === screenshareFeed.userId
204215
);
205216

206217
if (userMediaItem) {
207218
userMediaItem.presenter = true;
208219
}
209220

210-
participants.push({
211-
id: callFeed.stream.id,
212-
callFeed,
221+
tileDescriptors.push({
222+
id: screenshareFeed.stream.id,
223+
member: userMediaItem?.member,
224+
callFeed: screenshareFeed,
213225
focused: true,
214-
isLocal: callFeed.isLocal(),
226+
isLocal: screenshareFeed.isLocal(),
215227
presenter: false,
216228
});
217229
}
218230

219-
return participants;
220-
}, [userMediaFeeds, activeSpeaker, screenshareFeeds]);
231+
return tileDescriptors;
232+
}, [client, participants, userMediaFeeds, activeSpeaker, screenshareFeeds]);
221233

222234
// The maximised participant: either the participant that the user has
223235
// manually put in fullscreen, or the focused (active) participant if the
@@ -281,7 +293,13 @@ export function InCallView({
281293

282294
return (
283295
<VideoGrid items={items} layout={layout} disableAnimations={isSafari}>
284-
{({ item, ...rest }: { item: Participant; [x: string]: unknown }) => (
296+
{({
297+
item,
298+
...rest
299+
}: {
300+
item: TileDescriptor;
301+
[x: string]: unknown;
302+
}) => (
285303
<VideoTileContainer
286304
key={item.id}
287305
item={item}

src/room/useGroupCall.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ export interface UseGroupCallReturnType {
5151
requestingScreenshare: boolean;
5252
isScreensharing: boolean;
5353
screenshareFeeds: CallFeed[];
54-
localScreenshareFeed: CallFeed;
5554
localDesktopCapturerSourceId: string;
5655
participants: RoomMember[];
5756
hasLocalParticipant: boolean;
@@ -68,7 +67,6 @@ interface State {
6867
microphoneMuted: boolean;
6968
localVideoMuted: boolean;
7069
screenshareFeeds: CallFeed[];
71-
localScreenshareFeed: CallFeed;
7270
localDesktopCapturerSourceId: string;
7371
isScreensharing: boolean;
7472
requestingScreenshare: boolean;
@@ -89,7 +87,6 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
8987
localVideoMuted,
9088
isScreensharing,
9189
screenshareFeeds,
92-
localScreenshareFeed,
9390
localDesktopCapturerSourceId,
9491
participants,
9592
hasLocalParticipant,
@@ -107,7 +104,6 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
107104
localVideoMuted: false,
108105
isScreensharing: false,
109106
screenshareFeeds: [],
110-
localScreenshareFeed: null,
111107
localDesktopCapturerSourceId: null,
112108
requestingScreenshare: false,
113109
participants: [],
@@ -135,7 +131,6 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
135131
microphoneMuted: groupCall.isMicrophoneMuted(),
136132
localVideoMuted: groupCall.isLocalVideoMuted(),
137133
isScreensharing: groupCall.isScreensharing(),
138-
localScreenshareFeed: groupCall.localScreenshareFeed,
139134
localDesktopCapturerSourceId: groupCall.localDesktopCapturerSourceId,
140135
screenshareFeeds: [...groupCall.screenshareFeeds],
141136
participants: [...groupCall.participants],
@@ -172,12 +167,11 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
172167

173168
function onLocalScreenshareStateChanged(
174169
isScreensharing: boolean,
175-
localScreenshareFeed: CallFeed,
170+
_localScreenshareFeed: CallFeed,
176171
localDesktopCapturerSourceId: string
177172
): void {
178173
updateState({
179174
isScreensharing,
180-
localScreenshareFeed,
181175
localDesktopCapturerSourceId,
182176
});
183177
}
@@ -228,7 +222,6 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
228222
microphoneMuted: groupCall.isMicrophoneMuted(),
229223
localVideoMuted: groupCall.isLocalVideoMuted(),
230224
isScreensharing: groupCall.isScreensharing(),
231-
localScreenshareFeed: groupCall.localScreenshareFeed,
232225
localDesktopCapturerSourceId: groupCall.localDesktopCapturerSourceId,
233226
screenshareFeeds: [...groupCall.screenshareFeeds],
234227
participants: [...groupCall.participants],
@@ -412,7 +405,6 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
412405
requestingScreenshare,
413406
isScreensharing,
414407
screenshareFeeds,
415-
localScreenshareFeed,
416408
localDesktopCapturerSourceId,
417409
participants,
418410
hasLocalParticipant,

src/video-grid/AudioContainer.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ limitations under the License.
1616

1717
import React, { FC, useEffect, useRef } from "react";
1818

19-
import { Participant } from "../room/InCallView";
19+
import { TileDescriptor } from "../room/InCallView";
2020
import { useCallFeed } from "./useCallFeed";
2121
import { useMediaStreamTrackCount } from "./useMediaStream";
2222

2323
// XXX: These in fact do not render anything but to my knowledge this is the
2424
// only way to a hook on an array
2525

2626
interface AudioForParticipantProps {
27-
item: Participant;
27+
item: TileDescriptor;
2828
audioContext: AudioContext;
2929
audioDestination: AudioNode;
3030
}
@@ -78,7 +78,7 @@ export const AudioForParticipant: FC<AudioForParticipantProps> = ({
7878
};
7979

8080
interface AudioContainerProps {
81-
items: Participant[];
81+
items: TileDescriptor[];
8282
audioContext: AudioContext;
8383
audioDestination: AudioNode;
8484
}

src/video-grid/VideoGrid.stories.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ limitations under the License.
1616

1717
import React, { useState } from "react";
1818
import { useMemo } from "react";
19+
import { RoomMember } from "matrix-js-sdk";
1920

2021
import { VideoGrid, useVideoGridLayout } from "./VideoGrid";
2122
import { VideoTile } from "./VideoTile";
2223
import { Button } from "../button";
23-
import { Participant } from "../room/InCallView";
24+
import { TileDescriptor } from "../room/InCallView";
2425

2526
export default {
2627
title: "VideoGrid",
@@ -33,10 +34,11 @@ export const ParticipantsTest = () => {
3334
const { layout, setLayout } = useVideoGridLayout(false);
3435
const [participantCount, setParticipantCount] = useState(1);
3536

36-
const items: Participant[] = useMemo(
37+
const items: TileDescriptor[] = useMemo(
3738
() =>
3839
new Array(participantCount).fill(undefined).map((_, i) => ({
3940
id: (i + 1).toString(),
41+
member: new RoomMember("!fake:room.id", `@user${i}:fake.dummy`),
4042
focused: false,
4143
presenter: false,
4244
})),
@@ -77,6 +79,7 @@ export const ParticipantsTest = () => {
7779
key={item.id}
7880
name={`User ${item.id}`}
7981
disableSpeakingIndicator={items.length < 3}
82+
hasFeed={true}
8083
{...rest}
8184
/>
8285
)}

src/video-grid/VideoGrid.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { ReactDOMAttributes } from "@use-gesture/react/dist/declarations/src/typ
2323

2424
import styles from "./VideoGrid.module.css";
2525
import { Layout } from "../room/GridLayoutMenu";
26-
import { Participant } from "../room/InCallView";
26+
import { TileDescriptor } from "../room/InCallView";
2727

2828
interface TilePosition {
2929
x: number;
@@ -36,7 +36,7 @@ interface TilePosition {
3636
interface Tile {
3737
key: Key;
3838
order: number;
39-
item: Participant;
39+
item: TileDescriptor;
4040
remove: boolean;
4141
focused: boolean;
4242
presenter: boolean;
@@ -693,12 +693,12 @@ interface ChildrenProperties extends ReactDOMAttributes {
693693
};
694694
width: number;
695695
height: number;
696-
item: Participant;
696+
item: TileDescriptor;
697697
[index: string]: unknown;
698698
}
699699

700700
interface VideoGridProps {
701-
items: Participant[];
701+
items: TileDescriptor[];
702702
layout: Layout;
703703
disableAnimations?: boolean;
704704
children: (props: ChildrenProperties) => React.ReactNode;

src/video-grid/VideoTile.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { AudioButton, FullscreenButton } from "../button/Button";
2626

2727
interface Props {
2828
name: string;
29+
hasFeed: Boolean;
2930
speaking?: boolean;
3031
audioMuted?: boolean;
3132
videoMuted?: boolean;
@@ -47,6 +48,7 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
4748
(
4849
{
4950
name,
51+
hasFeed,
5052
speaking,
5153
audioMuted,
5254
videoMuted,
@@ -90,6 +92,8 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
9092
}
9193
}
9294

95+
const caption = hasFeed ? name : t("{{name}} (Connecting...)", { name });
96+
9397
return (
9498
<animated.div
9599
className={classNames(styles.videoTile, className, {
@@ -120,7 +124,7 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
120124
<div className={classNames(styles.infoBubble, styles.memberName)}>
121125
{audioMuted && !videoMuted && <MicMutedIcon />}
122126
{videoMuted && <VideoMutedIcon />}
123-
<span title={name}>{name}</span>
127+
<span title={caption}>{caption}</span>
124128
</div>
125129
))}
126130
<video ref={mediaRef} playsInline disablePictureInPicture />

0 commit comments

Comments
 (0)