fix(voice): drive call tiles from gateway voice state (#2406)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-02 17:39:48 +02:00
1 parent 917e437939
commit 5bc1f21d46
37 files changed
+138 -119

No files matched your search

@@ -23,6 +23,7 @@ import MediaEngine, {useMediaEngineVersion, useVoiceEngineV2Model} from '@app/fe
import {selectVoiceEngineV2AppEffectiveSelfMuteForVoiceStatePayload} from '@app/features/voice/engine/v2/VoiceEngineV2AppSelectors';
import LocalVoiceState from '@app/features/voice/state/LocalVoiceState';
import {isParticipantVoicePermissionMuted} from '@app/features/voice/utils/VoicePermissionUtils';
import {ME} from '@fluxer/constants/src/AppConstants';
import {msg} from '@lingui/core/macro';
import {useLingui} from '@lingui/react/macro';
import {clsx} from 'clsx';
@@ -212,20 +213,24 @@ export function useVoiceParticipantAvatarEntries({
const localSelfDeaf = LocalVoiceState.getSelfDeaf();
const sortSnapshotRef = useRef(createVoiceParticipantSortSnapshot());
return useMemo(() => {
if (!channelId) return [];
const nextEntries: Array<VoiceParticipantAvatarEntry> = [];
for (const snapshot of Object.values(participantSnapshots)) {
if (!snapshot.userId || !snapshot.connectionId) continue;
const user = Users.getUser(snapshot.userId);
for (const [connectionId, voiceState] of Object.entries(
MediaEngine.getAllVoiceStatesInChannel(guildId ?? ME, channelId),
)) {
if (!voiceState.user_id) continue;
const user = Users.getUser(voiceState.user_id);
if (!user) continue;
const voiceState = connectionVoiceStates[snapshot.connectionId] ?? null;
const snapshot = MediaEngine.getParticipantByUserIdAndConnectionId(voiceState.user_id, connectionId) ?? null;
const isLocal = connectionId === MediaEngine.connectionId;
const permissionMuted = isParticipantVoicePermissionMuted({
voiceState,
guildId,
channelId,
isCurrentUser: snapshot.isLocal,
isCurrentUser: isLocal,
});
const entryVoiceState = resolveVoiceParticipantAvatarEntryVoiceState({
snapshot,
snapshot: {...(snapshot ?? {}), isLocal},
voiceState,
permissionMuted,
localEffectiveSelfMute,
@@ -233,12 +238,12 @@ export function useVoiceParticipantAvatarEntries({
});
nextEntries.push({
user,
userId: snapshot.userId,
connectionId: snapshot.connectionId,
userId: voiceState.user_id,
connectionId,
speaking: entryVoiceState.speaking,
hasCamera: snapshot.isCameraEnabled,
hasScreenShare: snapshot.isScreenShareEnabled,
isLocal: snapshot.isLocal,
hasCamera: snapshot?.isCameraEnabled ?? false,
hasScreenShare: snapshot?.isScreenShareEnabled ?? false,
isLocal,
selfMute: entryVoiceState.selfMute,
selfDeaf: entryVoiceState.selfDeaf,
});
@@ -629,7 +629,7 @@ const VoiceParticipantTileInner = observer(function VoiceParticipantTileInner({
);
const participantMenuSource = useMemo<VoiceParticipantMenuSource>(() => {
if (!isScreenShare) {
return isCameraTile && isCameraPublicationActive ? {kind: 'camera'} : {kind: 'participant'};
return isCameraTile && isCameraActive ? {kind: 'camera'} : {kind: 'participant'};
}
if (isOwnScreenShare) {
return {kind: 'screen-share', streamKey, state: {kind: 'own'}};
@@ -655,7 +655,7 @@ const VoiceParticipantTileInner = observer(function VoiceParticipantTileInner({
}, [
hasScreenShareAudio,
identity,
isCameraPublicationActive,
isCameraActive,
isCameraTile,
isOwnScreenShare,
isScreenShare,
@@ -230,10 +230,24 @@ export function useVoiceCallTracksAndLayout({channel, expandedUserIds}: UseVoice
const screenSharePublicationMigrationVersion = ScreenSharePublicationMigration.version;
const localConnectionId = MediaEngine.connectionId;
const localSelfStream = LocalVoiceState.getSelfStream();
const {screenShareTracks, cameraTracksAll} = useMemo(
() => splitVoiceCallRenderableTracks(renderableTracks),
[renderableTracks, screenSharePublicationMigrationVersion],
);
const {screenShareTracks, cameraTracksAll} = useMemo(() => {
const split = splitVoiceCallRenderableTracks(renderableTracks);
const activeScreenShareTracks = split.screenShareTracks.filter((tr) => {
const connectionId = parseVoiceParticipantIdentity(tr.participant.identity).connectionId;
if (!connectionId) return true;
if (connectionId === localConnectionId) return localSelfStream;
const voiceState = connectionVoiceStates[connectionId];
return Boolean(voiceState?.self_stream && voiceState.channel_id === channel.id);
});
return {screenShareTracks: activeScreenShareTracks, cameraTracksAll: split.cameraTracksAll};
}, [
renderableTracks,
screenSharePublicationMigrationVersion,
connectionVoiceStates,
localConnectionId,
localSelfStream,
channel.id,
]);
const activeScreenShareState = useMemo(() => {
const connectionIds = new Set<string>();
const participantIdentities = new Set<string>();