daily-examples/custom/shared/contexts/callState.js

87 lines
2.5 KiB
JavaScript

/**
* Call State
* ---
* Duck file that keeps state of call participants
*/
export const ACTION_PARTICIPANT_JOINED = 'ACTION_PARTICIPANT_JOINED';
export const ACTION_PARTICIPANT_UPDATED = 'ACTION_PARTICIPANT_UPDATED';
export const ACTION_PARTICIPANTED_LEFT = 'ACTION_PARTICIPANT_LEFT';
export const initialCallState = {
audioTracks: {},
videoTracks: {},
callItems: {},
fatalError: false,
};
export function isLocal(id) {
return id === 'local';
}
function getCallItems(newParticipants, prevCallItems) {
const callItems = {};
const entries = Object.entries(newParticipants);
entries.forEach(([id, participant]) => {
const prevState = prevCallItems[id];
const hasLoaded = !prevState?.isLoading;
const missingTracks = !(participant.audioTrack || participant.videoTrack);
const joined = prevState?.joined || new Date().getTime() / 1000;
const local = isLocal(id);
callItems[id] = {
id,
name: participant.user_name || 'Guest',
audioTrack: participant.audioTrack,
videoTrack: participant.videoTrack,
hasNameSet: !!participant.user_name,
isActiveSpeaker: !!prevState?.isActiveSpeaker,
isCamMuted: !participant.video,
isLoading: !hasLoaded && missingTracks,
isLocal: local,
isMicMuted: !participant.audio,
isOwner: !!participant.owner,
isRecording: !!participant.record,
lastActiveDate: prevState?.lastActiveDate ?? null,
mutedByHost: participant?.tracks?.audio?.off?.byRemoteRequest,
isScreenshare: false,
joined,
};
if (participant.screenVideoTrack || participant.screenAudioTrack) {
callItems[`${id}-screen`] = {
audioTrack: participant.tracks.screenAudio.persistentTrack,
hasNameSet: null,
id: `${id}-screen`,
isLoading: false,
isLocal: local,
isScreenshare: true,
lastActiveDate: prevState?.lastActiveDate ?? null,
name: participant.user_name,
videoTrack: participant.screenVideoTrack,
};
}
});
return callItems;
}
export function isScreenShare(id) {
return id.endsWith('-screen');
}
export function containsScreenShare(participants) {
return Object.keys(participants).some((id) => isScreenShare(id));
}
export function callReducer(state, action) {
switch (action.type) {
case ACTION_PARTICIPANT_UPDATED:
return {
...state,
callItems: getCallItems(action.participants, state.callItems),
};
default:
throw new Error();
}
}