fixed participantState

This commit is contained in:
J Taylor 2021-06-30 12:42:12 +01:00
parent e8fd32ad56
commit aa53966923
3 changed files with 122 additions and 104 deletions

View File

@ -8,6 +8,7 @@
* - A session id for each remote participant
* - "<id>-screen" for each shared screen
*/
import fasteq from 'fast-deep-equal';
import {
DEVICE_STATE_OFF,
DEVICE_STATE_BLOCKED,
@ -15,8 +16,9 @@ import {
} from './useDevices';
const initialParticipantsState = {
participants: {
local: {
lastPendingUnknownActiveSpeaker: null,
participants: [
{
camMutedByHost: false,
hasNameSet: false,
id: 'local',
@ -31,9 +33,9 @@ const initialParticipantsState = {
lastActiveDate: null,
micMutedByHost: false,
name: '',
position: 1,
},
},
],
screens: [],
};
// --- Derived data ---
@ -63,36 +65,7 @@ function getMaxPosition(participants) {
);
}
function getUpdatedParticipant(participant, participants) {
const id = getId(participant);
const prevItem = participants[id];
const { local } = participant;
const { audio, video } = participant.tracks;
return {
...prevItem,
camMutedByHost: video?.off?.byRemoteRequest,
hasNameSet: !!participant.user_name,
id,
isCamMuted:
video?.state === DEVICE_STATE_OFF ||
video?.state === DEVICE_STATE_BLOCKED,
isLoading:
audio?.state === DEVICE_STATE_LOADING ||
video?.state === DEVICE_STATE_LOADING,
isLocal: local,
isMicMuted:
audio?.state === DEVICE_STATE_OFF ||
audio?.state === DEVICE_STATE_BLOCKED,
isOwner: !!participant.owner,
isRecording: !!participant.record,
micMutedByHost: audio?.off?.byRemoteRequest,
name: participant.user_name,
};
}
function getNewParticipant(participant, participants) {
function getNewParticipant(participant) {
const id = getId(participant);
const { local } = participant;
@ -119,11 +92,41 @@ function getNewParticipant(participant, participants) {
lastActiveDate: null,
micMutedByHost: audio?.off?.byRemoteRequest,
name: participant.user_name,
position: local ? 0 : getMaxPosition(participants) + 1,
};
}
function getScreenItem(participant, participants) {
function getUpdatedParticipant(participant, participants) {
const id = getId(participant);
const prevItem = participants.find((p) => p.id === id);
// In case we haven't set up this participant, yet.
if (!prevItem) return getNewParticipant(participant);
const { local } = participant;
const { audio, video } = participant.tracks;
return {
...prevItem,
camMutedByHost: video?.off?.byRemoteRequest,
hasNameSet: !!participant.user_name,
id,
isCamMuted:
video?.state === DEVICE_STATE_OFF ||
video?.state === DEVICE_STATE_BLOCKED,
isLoading:
audio?.state === DEVICE_STATE_LOADING ||
video?.state === DEVICE_STATE_LOADING,
isLocal: local,
isMicMuted:
audio?.state === DEVICE_STATE_OFF ||
audio?.state === DEVICE_STATE_BLOCKED,
isOwner: !!participant.owner,
isRecording: !!participant.record,
micMutedByHost: audio?.off?.byRemoteRequest,
name: participant.user_name,
};
}
function getScreenItem(participant) {
const id = getId(participant);
return {
hasNameSet: null,
@ -133,7 +136,6 @@ function getScreenItem(participant, participants) {
isScreenshare: true,
lastActiveDate: null,
name: participant.user_name,
position: getMaxPosition(participants) + 1,
};
}
@ -151,49 +153,66 @@ function participantsReducer(prevState, action) {
switch (action.type) {
case ACTIVE_SPEAKER: {
const { participants, ...state } = prevState;
if (!action.id) return prevState;
if (!action.id)
return {
...prevState,
lastPendingUnknownActiveSpeaker: null,
};
const date = new Date();
const isParticipantKnown = participants.some((p) => p.id === action.id);
return {
...state,
participants: Object.keys(participants).reduce(
(items, id) => ({
...items,
[id]: {
...participants[id],
isActiveSpeaker: id === action.id,
lastActiveDate:
id === action.id
? new Date()
: participants[id]?.lastActiveDate,
lastPendingUnknownActiveSpeaker: isParticipantKnown
? null
: {
date,
id: action.id,
},
}),
{}
),
participants: participants.map((p) => ({
...p,
isActiveSpeaker: p.id === action.id,
lastActiveDate: p.id === action.id ? date : p?.lastActiveDate,
})),
};
}
case PARTICIPANT_JOINED: {
const item = getNewParticipant(
action.participant,
prevState.participants
);
const { id } = item;
const screenId = getScreenId(id);
const item = getNewParticipant(action.participant);
const newParticipants = {
...prevState.participants,
[id]: item,
};
const participants = [...prevState.participants];
const screens = [...prevState.screens];
const isPendingActiveSpeaker =
item.id === prevState.lastPendingUnknownActiveSpeaker?.id;
if (isPendingActiveSpeaker) {
item.isActiveSpeaker = true;
item.lastActiveDate = prevState.lastPendingUnknownActiveSpeaker?.date;
}
if (item.isCamMuted) {
participants.push(item);
} else {
const firstInactiveCamOffIndex = prevState.participants.findIndex(
(p) => p.isCamMuted && !p.isLocal && !p.isActiveSpeaker
);
if (firstInactiveCamOffIndex >= 0) {
participants.splice(firstInactiveCamOffIndex, 0, item);
} else {
participants.push(item);
}
}
// Participant is sharing screen
if (action.participant.screen) {
newParticipants[screenId] = getScreenItem(
action.participant,
newParticipants
);
screens.push(getScreenItem(action.participant));
}
return {
...prevState,
participants: newParticipants,
lastPendingUnknownActiveSpeaker: isPendingActiveSpeaker
? null
: prevState.lastPendingUnknownActiveSpeaker,
participants,
screens,
};
}
case PARTICIPANT_UPDATED: {
@ -204,60 +223,58 @@ function participantsReducer(prevState, action) {
const { id } = item;
const screenId = getScreenId(id);
const newParticipants = {
...prevState.participants,
};
newParticipants[id] = item;
const participants = [...prevState.participants];
const idx = participants.findIndex((p) => p.id === id);
participants[idx] = item;
const screens = [...prevState.screens];
const screenIdx = screens.findIndex((s) => s.id === screenId);
if (action.participant.screen) {
newParticipants[screenId] = getScreenItem(
action.participant,
newParticipants
);
} else {
delete newParticipants[screenId];
const screenItem = getScreenItem(action.participant);
if (screenIdx >= 0) {
screens[screenIdx] = screenItem;
} else {
screens.push(screenItem);
}
} else if (screenIdx >= 0) {
screens.splice(screenIdx, 1);
}
return {
const newState = {
...prevState,
participants: newParticipants,
participants,
screens,
};
if (fasteq(newState, prevState)) {
return prevState;
}
return newState;
}
case PARTICIPANT_LEFT: {
const id = getId(action.participant);
const screenId = getScreenId(id);
const { ...participants } = prevState.participants;
delete participants[id];
delete participants[screenId];
return {
...prevState,
participants,
participants: [...prevState.participants].filter((p) => p.id !== id),
screens: [...prevState.screens].filter((s) => s.id !== screenId),
};
}
case SWAP_POSITION: {
const { participants, ...state } = prevState;
const participants = [...prevState.participants];
if (!action.id1 || !action.id2) return prevState;
const pos1 = participants[action.id1]?.position;
const pos2 = participants[action.id2]?.position;
if (!pos1 || !pos2) return prevState;
const idx1 = participants.findIndex((p) => p.id === action.id1);
const idx2 = participants.findIndex((p) => p.id === action.id2);
if (idx1 === -1 || idx2 === -1) return prevState;
const tmp = participants[idx1];
participants[idx1] = participants[idx2];
participants[idx2] = tmp;
return {
...state,
participants: Object.keys(participants).reduce((items, id) => {
let { position } = participants[id];
if (action.id1 === id) {
position = pos2;
}
if (action.id2 === id) {
position = pos1;
}
return {
...items,
[id]: {
...participants[id],
position,
},
};
}, {}),
...prevState,
participants,
};
}
default:

View File

@ -7,6 +7,7 @@
"@daily-co/daily-js": "^0.12.0",
"classnames": "^2.3.1",
"debounce": "^1.2.1",
"fast-deep-equal": "^3.1.3",
"nanoid": "^3.1.23",
"no-scroll": "^2.1.1",
"prop-types": "^15.7.2",

View File

@ -1532,7 +1532,7 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
md5.js "^1.3.4"
safe-buffer "^5.1.1"
fast-deep-equal@^3.1.1:
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==