fixed participantState
This commit is contained in:
parent
e8fd32ad56
commit
aa53966923
|
|
@ -8,6 +8,7 @@
|
||||||
* - A session id for each remote participant
|
* - A session id for each remote participant
|
||||||
* - "<id>-screen" for each shared screen
|
* - "<id>-screen" for each shared screen
|
||||||
*/
|
*/
|
||||||
|
import fasteq from 'fast-deep-equal';
|
||||||
import {
|
import {
|
||||||
DEVICE_STATE_OFF,
|
DEVICE_STATE_OFF,
|
||||||
DEVICE_STATE_BLOCKED,
|
DEVICE_STATE_BLOCKED,
|
||||||
|
|
@ -15,8 +16,9 @@ import {
|
||||||
} from './useDevices';
|
} from './useDevices';
|
||||||
|
|
||||||
const initialParticipantsState = {
|
const initialParticipantsState = {
|
||||||
participants: {
|
lastPendingUnknownActiveSpeaker: null,
|
||||||
local: {
|
participants: [
|
||||||
|
{
|
||||||
camMutedByHost: false,
|
camMutedByHost: false,
|
||||||
hasNameSet: false,
|
hasNameSet: false,
|
||||||
id: 'local',
|
id: 'local',
|
||||||
|
|
@ -31,9 +33,9 @@ const initialParticipantsState = {
|
||||||
lastActiveDate: null,
|
lastActiveDate: null,
|
||||||
micMutedByHost: false,
|
micMutedByHost: false,
|
||||||
name: '',
|
name: '',
|
||||||
position: 1,
|
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
|
screens: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Derived data ---
|
// --- Derived data ---
|
||||||
|
|
@ -63,36 +65,7 @@ function getMaxPosition(participants) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUpdatedParticipant(participant, participants) {
|
function getNewParticipant(participant) {
|
||||||
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) {
|
|
||||||
const id = getId(participant);
|
const id = getId(participant);
|
||||||
|
|
||||||
const { local } = participant;
|
const { local } = participant;
|
||||||
|
|
@ -119,11 +92,41 @@ function getNewParticipant(participant, participants) {
|
||||||
lastActiveDate: null,
|
lastActiveDate: null,
|
||||||
micMutedByHost: audio?.off?.byRemoteRequest,
|
micMutedByHost: audio?.off?.byRemoteRequest,
|
||||||
name: participant.user_name,
|
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);
|
const id = getId(participant);
|
||||||
return {
|
return {
|
||||||
hasNameSet: null,
|
hasNameSet: null,
|
||||||
|
|
@ -133,7 +136,6 @@ function getScreenItem(participant, participants) {
|
||||||
isScreenshare: true,
|
isScreenshare: true,
|
||||||
lastActiveDate: null,
|
lastActiveDate: null,
|
||||||
name: participant.user_name,
|
name: participant.user_name,
|
||||||
position: getMaxPosition(participants) + 1,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,49 +153,66 @@ function participantsReducer(prevState, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ACTIVE_SPEAKER: {
|
case ACTIVE_SPEAKER: {
|
||||||
const { participants, ...state } = prevState;
|
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 {
|
return {
|
||||||
...state,
|
...state,
|
||||||
participants: Object.keys(participants).reduce(
|
lastPendingUnknownActiveSpeaker: isParticipantKnown
|
||||||
(items, id) => ({
|
? null
|
||||||
...items,
|
: {
|
||||||
[id]: {
|
date,
|
||||||
...participants[id],
|
id: action.id,
|
||||||
isActiveSpeaker: id === action.id,
|
|
||||||
lastActiveDate:
|
|
||||||
id === action.id
|
|
||||||
? new Date()
|
|
||||||
: participants[id]?.lastActiveDate,
|
|
||||||
},
|
},
|
||||||
}),
|
participants: participants.map((p) => ({
|
||||||
{}
|
...p,
|
||||||
),
|
isActiveSpeaker: p.id === action.id,
|
||||||
|
lastActiveDate: p.id === action.id ? date : p?.lastActiveDate,
|
||||||
|
})),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case PARTICIPANT_JOINED: {
|
case PARTICIPANT_JOINED: {
|
||||||
const item = getNewParticipant(
|
const item = getNewParticipant(action.participant);
|
||||||
action.participant,
|
|
||||||
prevState.participants
|
|
||||||
);
|
|
||||||
const { id } = item;
|
|
||||||
const screenId = getScreenId(id);
|
|
||||||
|
|
||||||
const newParticipants = {
|
const participants = [...prevState.participants];
|
||||||
...prevState.participants,
|
const screens = [...prevState.screens];
|
||||||
[id]: item,
|
|
||||||
};
|
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
|
// Participant is sharing screen
|
||||||
if (action.participant.screen) {
|
if (action.participant.screen) {
|
||||||
newParticipants[screenId] = getScreenItem(
|
screens.push(getScreenItem(action.participant));
|
||||||
action.participant,
|
|
||||||
newParticipants
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...prevState,
|
...prevState,
|
||||||
participants: newParticipants,
|
lastPendingUnknownActiveSpeaker: isPendingActiveSpeaker
|
||||||
|
? null
|
||||||
|
: prevState.lastPendingUnknownActiveSpeaker,
|
||||||
|
participants,
|
||||||
|
screens,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case PARTICIPANT_UPDATED: {
|
case PARTICIPANT_UPDATED: {
|
||||||
|
|
@ -204,60 +223,58 @@ function participantsReducer(prevState, action) {
|
||||||
const { id } = item;
|
const { id } = item;
|
||||||
const screenId = getScreenId(id);
|
const screenId = getScreenId(id);
|
||||||
|
|
||||||
const newParticipants = {
|
const participants = [...prevState.participants];
|
||||||
...prevState.participants,
|
const idx = participants.findIndex((p) => p.id === id);
|
||||||
};
|
participants[idx] = item;
|
||||||
newParticipants[id] = item;
|
|
||||||
|
const screens = [...prevState.screens];
|
||||||
|
const screenIdx = screens.findIndex((s) => s.id === screenId);
|
||||||
|
|
||||||
if (action.participant.screen) {
|
if (action.participant.screen) {
|
||||||
newParticipants[screenId] = getScreenItem(
|
const screenItem = getScreenItem(action.participant);
|
||||||
action.participant,
|
if (screenIdx >= 0) {
|
||||||
newParticipants
|
screens[screenIdx] = screenItem;
|
||||||
);
|
} else {
|
||||||
} else {
|
screens.push(screenItem);
|
||||||
delete newParticipants[screenId];
|
}
|
||||||
|
} else if (screenIdx >= 0) {
|
||||||
|
screens.splice(screenIdx, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const newState = {
|
||||||
...prevState,
|
...prevState,
|
||||||
participants: newParticipants,
|
participants,
|
||||||
|
screens,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (fasteq(newState, prevState)) {
|
||||||
|
return prevState;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newState;
|
||||||
}
|
}
|
||||||
case PARTICIPANT_LEFT: {
|
case PARTICIPANT_LEFT: {
|
||||||
const id = getId(action.participant);
|
const id = getId(action.participant);
|
||||||
const screenId = getScreenId(id);
|
const screenId = getScreenId(id);
|
||||||
const { ...participants } = prevState.participants;
|
|
||||||
delete participants[id];
|
|
||||||
delete participants[screenId];
|
|
||||||
return {
|
return {
|
||||||
...prevState,
|
...prevState,
|
||||||
participants,
|
participants: [...prevState.participants].filter((p) => p.id !== id),
|
||||||
|
screens: [...prevState.screens].filter((s) => s.id !== screenId),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case SWAP_POSITION: {
|
case SWAP_POSITION: {
|
||||||
const { participants, ...state } = prevState;
|
const participants = [...prevState.participants];
|
||||||
if (!action.id1 || !action.id2) return prevState;
|
if (!action.id1 || !action.id2) return prevState;
|
||||||
const pos1 = participants[action.id1]?.position;
|
const idx1 = participants.findIndex((p) => p.id === action.id1);
|
||||||
const pos2 = participants[action.id2]?.position;
|
const idx2 = participants.findIndex((p) => p.id === action.id2);
|
||||||
if (!pos1 || !pos2) return prevState;
|
if (idx1 === -1 || idx2 === -1) return prevState;
|
||||||
|
const tmp = participants[idx1];
|
||||||
|
participants[idx1] = participants[idx2];
|
||||||
|
participants[idx2] = tmp;
|
||||||
return {
|
return {
|
||||||
...state,
|
...prevState,
|
||||||
participants: Object.keys(participants).reduce((items, id) => {
|
participants,
|
||||||
let { position } = participants[id];
|
|
||||||
if (action.id1 === id) {
|
|
||||||
position = pos2;
|
|
||||||
}
|
|
||||||
if (action.id2 === id) {
|
|
||||||
position = pos1;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...items,
|
|
||||||
[id]: {
|
|
||||||
...participants[id],
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}, {}),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
"@daily-co/daily-js": "^0.12.0",
|
"@daily-co/daily-js": "^0.12.0",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"debounce": "^1.2.1",
|
"debounce": "^1.2.1",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
"nanoid": "^3.1.23",
|
"nanoid": "^3.1.23",
|
||||||
"no-scroll": "^2.1.1",
|
"no-scroll": "^2.1.1",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
|
|
|
||||||
|
|
@ -1532,7 +1532,7 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
|
||||||
md5.js "^1.3.4"
|
md5.js "^1.3.4"
|
||||||
safe-buffer "^5.1.1"
|
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"
|
version "3.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue