updated contexts
This commit is contained in:
parent
9e44a018b4
commit
e8fd32ad56
|
|
@ -26,7 +26,7 @@ import {
|
||||||
export const ParticipantsContext = createContext();
|
export const ParticipantsContext = createContext();
|
||||||
|
|
||||||
export const ParticipantsProvider = ({ children }) => {
|
export const ParticipantsProvider = ({ children }) => {
|
||||||
const { broadcast, callObject } = useCallState();
|
const { callObject } = useCallState();
|
||||||
const [state, dispatch] = useReducer(
|
const [state, dispatch] = useReducer(
|
||||||
participantsReducer,
|
participantsReducer,
|
||||||
initialParticipantsState
|
initialParticipantsState
|
||||||
|
|
@ -37,20 +37,17 @@ export const ParticipantsProvider = ({ children }) => {
|
||||||
/**
|
/**
|
||||||
* ALL participants (incl. shared screens) in a convenient array
|
* ALL participants (incl. shared screens) in a convenient array
|
||||||
*/
|
*/
|
||||||
const allParticipants = useDeepCompareMemo(
|
const allParticipants = useMemo(
|
||||||
() => Object.values(state.participants),
|
() => [...state.participants, ...state.screens],
|
||||||
[state?.participants]
|
[state?.participants, state?.screens]
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only return participants that should be visible in the call
|
* Only return participants that should be visible in the call
|
||||||
*/
|
*/
|
||||||
const participants = useDeepCompareMemo(
|
const participants = useDeepCompareMemo(
|
||||||
() =>
|
() => allParticipants.filter((p) => p?.isOwner),
|
||||||
!broadcast
|
[allParticipants]
|
||||||
? allParticipants
|
|
||||||
: allParticipants.filter((p) => p?.isOwner || p?.isScreenshare),
|
|
||||||
[broadcast, allParticipants]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -99,6 +96,19 @@ export const ParticipantsProvider = ({ children }) => {
|
||||||
|
|
||||||
const displayableParticipants = participants.filter((p) => !p?.isLocal);
|
const displayableParticipants = participants.filter((p) => !p?.isLocal);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isPresent &&
|
||||||
|
displayableParticipants.length > 0 &&
|
||||||
|
displayableParticipants.every((p) => p.isMicMuted && !p.lastActiveDate)
|
||||||
|
) {
|
||||||
|
// Return first cam on participant in case everybody is muted and nobody ever talked
|
||||||
|
// or first remote participant, in case everybody's cam is muted, too.
|
||||||
|
return (
|
||||||
|
displayableParticipants.find((p) => !p.isCamMuted) ??
|
||||||
|
displayableParticipants?.[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const sorted = displayableParticipants
|
const sorted = displayableParticipants
|
||||||
.sort((a, b) => sortByKey(a, b, 'lastActiveDate'))
|
.sort((a, b) => sortByKey(a, b, 'lastActiveDate'))
|
||||||
.reverse();
|
.reverse();
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,203 @@
|
||||||
|
/* global rtcpeers */
|
||||||
|
|
||||||
import React, {
|
import React, {
|
||||||
createContext,
|
createContext,
|
||||||
useCallback,
|
useCallback,
|
||||||
useContext,
|
useContext,
|
||||||
useEffect,
|
useEffect,
|
||||||
|
useMemo,
|
||||||
useReducer,
|
useReducer,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { sortByKey } from '../lib/sortByKey';
|
||||||
import { useCallState } from './CallProvider';
|
import { useCallState } from './CallProvider';
|
||||||
|
import { useParticipants } from './ParticipantsProvider';
|
||||||
|
import { isLocalId, isScreenId } from './participantsState';
|
||||||
import {
|
import {
|
||||||
initialTracksState,
|
initialTracksState,
|
||||||
REMOVE_TRACKS,
|
REMOVE_TRACKS,
|
||||||
TRACK_STARTED,
|
TRACK_STARTED,
|
||||||
TRACK_STOPPED,
|
TRACK_STOPPED,
|
||||||
UPDATE_TRACKS,
|
UPDATE_SUBSCRIPTIONS,
|
||||||
tracksReducer,
|
tracksReducer,
|
||||||
} from './tracksState';
|
} from './tracksState';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum amount of concurrently subscribed most recent speakers.
|
||||||
|
*/
|
||||||
|
const MAX_RECENT_SPEAKER_COUNT = 6;
|
||||||
|
/**
|
||||||
|
* Threshold up to which all videos will be subscribed.
|
||||||
|
* If the remote participant count passes this threshold,
|
||||||
|
* cam subscriptions are defined by UI view modes.
|
||||||
|
*/
|
||||||
|
const SUBSCRIBE_ALL_VIDEO_THRESHOLD = 9;
|
||||||
|
|
||||||
const TracksContext = createContext(null);
|
const TracksContext = createContext(null);
|
||||||
|
|
||||||
export const TracksProvider = ({ children }) => {
|
export const TracksProvider = ({ children }) => {
|
||||||
const { callObject } = useCallState();
|
const { callObject } = useCallState();
|
||||||
|
const { participants } = useParticipants();
|
||||||
const [state, dispatch] = useReducer(tracksReducer, initialTracksState);
|
const [state, dispatch] = useReducer(tracksReducer, initialTracksState);
|
||||||
|
|
||||||
|
const recentSpeakerIds = useMemo(
|
||||||
|
() =>
|
||||||
|
participants
|
||||||
|
.filter((p) => Boolean(p.lastActiveDate) && !p.isLocal)
|
||||||
|
.sort((a, b) => sortByKey(a, b, 'lastActiveDate'))
|
||||||
|
.slice(-MAX_RECENT_SPEAKER_COUNT)
|
||||||
|
.map((p) => p.id)
|
||||||
|
.reverse(),
|
||||||
|
[participants]
|
||||||
|
);
|
||||||
|
|
||||||
|
const pauseVideoTrack = useCallback((id) => {
|
||||||
|
/**
|
||||||
|
* Ignore undefined, local or screenshare.
|
||||||
|
*/
|
||||||
|
if (!id || isLocalId(id) || isScreenId(id)) return;
|
||||||
|
if (!rtcpeers.soup.implementationIsAcceptingCalls) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const consumer = rtcpeers.soup?.findConsumerForTrack(id, 'cam-video');
|
||||||
|
if (!consumer) return;
|
||||||
|
rtcpeers.soup?.pauseConsumer(consumer);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const resumeVideoTrack = useCallback(
|
||||||
|
(id) => {
|
||||||
|
/**
|
||||||
|
* Ignore undefined, local or screenshare.
|
||||||
|
*/
|
||||||
|
if (!id || isLocalId(id) || isScreenId(id)) return;
|
||||||
|
|
||||||
|
const videoTrack = callObject.participants()?.[id]?.tracks?.video;
|
||||||
|
if (!videoTrack?.subscribed) {
|
||||||
|
callObject.updateParticipant(id, {
|
||||||
|
setSubscribedTracks: true,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!rtcpeers.soup.implementationIsAcceptingCalls) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const consumer = rtcpeers.soup?.findConsumerForTrack(id, 'cam-video');
|
||||||
|
if (!consumer) return;
|
||||||
|
rtcpeers.soup?.resumeConsumer(consumer);
|
||||||
|
},
|
||||||
|
[callObject]
|
||||||
|
);
|
||||||
|
|
||||||
|
const remoteParticipantIds = useMemo(
|
||||||
|
() => participants.filter((p) => !p.isLocal).map((p) => p.id),
|
||||||
|
[participants]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates cam subscriptions based on passed ids.
|
||||||
|
*
|
||||||
|
* @param ids Array of ids to subscribe to, all others will be unsubscribed.
|
||||||
|
* @param pausedIds Array of ids that should be subscribed, but paused.
|
||||||
|
*/
|
||||||
|
const updateCamSubscriptions = useCallback(
|
||||||
|
(ids, pausedIds = []) => {
|
||||||
|
if (!callObject) return;
|
||||||
|
const subscribedIds =
|
||||||
|
remoteParticipantIds.length <= SUBSCRIBE_ALL_VIDEO_THRESHOLD
|
||||||
|
? [...remoteParticipantIds]
|
||||||
|
: [...ids, ...recentSpeakerIds];
|
||||||
|
const updates = remoteParticipantIds.reduce((u, id) => {
|
||||||
|
const shouldSubscribe = subscribedIds.includes(id);
|
||||||
|
const isSubscribed =
|
||||||
|
callObject.participants()?.[id]?.tracks?.video?.subscribed;
|
||||||
|
if (
|
||||||
|
isLocalId(id) ||
|
||||||
|
isScreenId(id) ||
|
||||||
|
(shouldSubscribe && isSubscribed)
|
||||||
|
)
|
||||||
|
return u;
|
||||||
|
const result = {
|
||||||
|
setSubscribedTracks: {
|
||||||
|
audio: true,
|
||||||
|
screenAudio: true,
|
||||||
|
screenVideo: true,
|
||||||
|
video: shouldSubscribe,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return { ...u, [id]: result };
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: UPDATE_SUBSCRIPTIONS,
|
||||||
|
subscriptions: {
|
||||||
|
video: subscribedIds.reduce((v, id) => {
|
||||||
|
const result = {
|
||||||
|
id,
|
||||||
|
paused: pausedIds.includes(id) || !ids.includes(id),
|
||||||
|
};
|
||||||
|
return { ...v, [id]: result };
|
||||||
|
}, {}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
ids
|
||||||
|
.filter((id) => !pausedIds.includes(id))
|
||||||
|
.forEach((id) => {
|
||||||
|
const p = callObject.participants()?.[id];
|
||||||
|
if (p?.tracks?.video?.subscribed) {
|
||||||
|
resumeVideoTrack(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
callObject.updateParticipants(updates);
|
||||||
|
},
|
||||||
|
[callObject, remoteParticipantIds, recentSpeakerIds, resumeVideoTrack]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!callObject) return false;
|
if (!callObject) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const trackStoppedQueue = [];
|
||||||
|
|
||||||
const handleTrackStarted = ({ participant, track }) => {
|
const handleTrackStarted = ({ participant, track }) => {
|
||||||
|
if (state.subscriptions.video?.[participant.session_id]?.paused) {
|
||||||
|
pauseVideoTrack(participant.session_id);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* If track for participant was recently stopped, remove it from queue,
|
||||||
|
* so we don't run into a stale state.
|
||||||
|
*/
|
||||||
|
const stoppingIdx = trackStoppedQueue.findIndex(
|
||||||
|
([p, t]) =>
|
||||||
|
p.session_id === participant.session_id && t.kind === track.kind
|
||||||
|
);
|
||||||
|
if (stoppingIdx >= 0) {
|
||||||
|
trackStoppedQueue.splice(stoppingIdx, 1);
|
||||||
|
}
|
||||||
dispatch({
|
dispatch({
|
||||||
type: TRACK_STARTED,
|
type: TRACK_STARTED,
|
||||||
participant,
|
participant,
|
||||||
track,
|
track,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const trackStoppedBatchInterval = setInterval(() => {
|
||||||
|
if (!trackStoppedQueue.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch({
|
||||||
|
type: TRACK_STOPPED,
|
||||||
|
items: trackStoppedQueue.splice(0, trackStoppedQueue.length),
|
||||||
|
});
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
const handleTrackStopped = ({ participant, track }) => {
|
const handleTrackStopped = ({ participant, track }) => {
|
||||||
if (participant) {
|
if (participant) {
|
||||||
dispatch({
|
trackStoppedQueue.push([participant, track]);
|
||||||
type: TRACK_STOPPED,
|
|
||||||
participant,
|
|
||||||
track,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleParticipantLeft = ({ participant }) => {
|
const handleParticipantLeft = ({ participant }) => {
|
||||||
|
|
@ -49,12 +206,6 @@ export const TracksProvider = ({ children }) => {
|
||||||
participant,
|
participant,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const handleParticipantUpdated = ({ participant }) => {
|
|
||||||
dispatch({
|
|
||||||
type: UPDATE_TRACKS,
|
|
||||||
participant,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const joinedSubscriptionQueue = [];
|
const joinedSubscriptionQueue = [];
|
||||||
|
|
||||||
|
|
@ -62,14 +213,15 @@ export const TracksProvider = ({ children }) => {
|
||||||
joinedSubscriptionQueue.push(participant.session_id);
|
joinedSubscriptionQueue.push(participant.session_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const batchInterval = setInterval(() => {
|
const joinBatchInterval = setInterval(() => {
|
||||||
if (!joinedSubscriptionQueue.length) return;
|
if (!joinedSubscriptionQueue.length) return;
|
||||||
const ids = joinedSubscriptionQueue.splice(0);
|
const ids = joinedSubscriptionQueue.splice(0);
|
||||||
const participants = callObject.participants();
|
const callParticipants = callObject.participants();
|
||||||
const updates = ids.reduce((o, id) => {
|
const updates = ids.reduce((o, id) => {
|
||||||
const { subscribed } = participants?.[id]?.tracks?.audio;
|
const { subscribed } = callParticipants?.[id]?.tracks?.audio;
|
||||||
|
const result = {};
|
||||||
if (!subscribed) {
|
if (!subscribed) {
|
||||||
o[id] = {
|
result[id] = {
|
||||||
setSubscribedTracks: {
|
setSubscribedTracks: {
|
||||||
audio: true,
|
audio: true,
|
||||||
screenAudio: true,
|
screenAudio: true,
|
||||||
|
|
@ -77,7 +229,11 @@ export const TracksProvider = ({ children }) => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return o;
|
|
||||||
|
if (rtcpeers?.getCurrentType?.() === 'peer-to-peer') {
|
||||||
|
result[id].setSubscribedTracks.video = true;
|
||||||
|
}
|
||||||
|
return { ...o, ...result };
|
||||||
}, {});
|
}, {});
|
||||||
callObject.updateParticipants(updates);
|
callObject.updateParticipants(updates);
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
@ -86,63 +242,23 @@ export const TracksProvider = ({ children }) => {
|
||||||
callObject.on('track-stopped', handleTrackStopped);
|
callObject.on('track-stopped', handleTrackStopped);
|
||||||
callObject.on('participant-joined', handleParticipantJoined);
|
callObject.on('participant-joined', handleParticipantJoined);
|
||||||
callObject.on('participant-left', handleParticipantLeft);
|
callObject.on('participant-left', handleParticipantLeft);
|
||||||
callObject.on('participant-updated', handleParticipantUpdated);
|
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(batchInterval);
|
clearInterval(joinBatchInterval);
|
||||||
|
clearInterval(trackStoppedBatchInterval);
|
||||||
callObject.off('track-started', handleTrackStarted);
|
callObject.off('track-started', handleTrackStarted);
|
||||||
callObject.off('track-stopped', handleTrackStopped);
|
callObject.off('track-stopped', handleTrackStopped);
|
||||||
callObject.off('participant-joined', handleParticipantJoined);
|
callObject.off('participant-joined', handleParticipantJoined);
|
||||||
callObject.off('participant-left', handleParticipantLeft);
|
callObject.off('participant-left', handleParticipantLeft);
|
||||||
callObject.off('participant-updated', handleParticipantUpdated);
|
|
||||||
};
|
};
|
||||||
}, [callObject]);
|
}, [callObject, pauseVideoTrack, state.subscriptions.video]);
|
||||||
|
|
||||||
const pauseVideoTrack = useCallback(
|
useEffect(() => {
|
||||||
(id) => {
|
Object.values(state.subscriptions.video).forEach(({ id, paused }) => {
|
||||||
if (!callObject) return;
|
if (paused) {
|
||||||
/**
|
pauseVideoTrack(id);
|
||||||
* Ignore undefined, local or screenshare.
|
|
||||||
*/
|
|
||||||
if (!id || id.includes('local') || id.includes('screen')) return;
|
|
||||||
// eslint-disable-next-line
|
|
||||||
if (!rtcpeers.soup.implementationIsAcceptingCalls) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line
|
});
|
||||||
const consumer = rtcpeers.soup?.findConsumerForTrack(id, 'cam-video');
|
}, [pauseVideoTrack, state.subscriptions.video]);
|
||||||
if (!consumer) return;
|
|
||||||
// eslint-disable-next-line
|
|
||||||
rtcpeers.soup?.pauseConsumer(consumer);
|
|
||||||
},
|
|
||||||
[callObject]
|
|
||||||
);
|
|
||||||
|
|
||||||
const resumeVideoTrack = useCallback(
|
|
||||||
(id) => {
|
|
||||||
/**
|
|
||||||
* Ignore undefined, local or screenshare.
|
|
||||||
*/
|
|
||||||
if (!id || id.includes('local') || id.includes('screen')) return;
|
|
||||||
|
|
||||||
const videoTrack = callObject.participants()?.[id]?.tracks?.video;
|
|
||||||
if (!videoTrack?.subscribed) {
|
|
||||||
callObject.updateParticipant(id, {
|
|
||||||
setSubscribedTracks: true,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line
|
|
||||||
if (!rtcpeers.soup.implementationIsAcceptingCalls) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line
|
|
||||||
const consumer = rtcpeers.soup?.findConsumerForTrack(id, 'cam-video');
|
|
||||||
if (!consumer) return;
|
|
||||||
// eslint-disable-next-line
|
|
||||||
rtcpeers.soup?.resumeConsumer(consumer);
|
|
||||||
},
|
|
||||||
[callObject]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TracksContext.Provider
|
<TracksContext.Provider
|
||||||
|
|
@ -150,7 +266,10 @@ export const TracksProvider = ({ children }) => {
|
||||||
audioTracks: state.audioTracks,
|
audioTracks: state.audioTracks,
|
||||||
pauseVideoTrack,
|
pauseVideoTrack,
|
||||||
resumeVideoTrack,
|
resumeVideoTrack,
|
||||||
|
remoteParticipantIds,
|
||||||
|
updateCamSubscriptions,
|
||||||
videoTracks: state.videoTracks,
|
videoTracks: state.videoTracks,
|
||||||
|
recentSpeakerIds,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,14 @@ function getScreenId(id) {
|
||||||
return `${id}-screen`;
|
return `${id}-screen`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isLocalId(id) {
|
||||||
|
return typeof id === 'string' && id === 'local';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isScreenId(id) {
|
||||||
|
return typeof id === 'string' && id.endsWith('-screen');
|
||||||
|
}
|
||||||
|
|
||||||
// ---Helpers ---
|
// ---Helpers ---
|
||||||
|
|
||||||
function getMaxPosition(participants) {
|
function getMaxPosition(participants) {
|
||||||
|
|
@ -261,10 +269,12 @@ export {
|
||||||
ACTIVE_SPEAKER,
|
ACTIVE_SPEAKER,
|
||||||
getId,
|
getId,
|
||||||
getScreenId,
|
getScreenId,
|
||||||
|
isLocalId,
|
||||||
|
isScreenId,
|
||||||
|
participantsReducer,
|
||||||
initialParticipantsState,
|
initialParticipantsState,
|
||||||
PARTICIPANT_JOINED,
|
PARTICIPANT_JOINED,
|
||||||
PARTICIPANT_LEFT,
|
PARTICIPANT_LEFT,
|
||||||
PARTICIPANT_UPDATED,
|
PARTICIPANT_UPDATED,
|
||||||
participantsReducer,
|
|
||||||
SWAP_POSITION,
|
SWAP_POSITION,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ import { getId, getScreenId } from './participantsState';
|
||||||
const initialTracksState = {
|
const initialTracksState = {
|
||||||
audioTracks: {},
|
audioTracks: {},
|
||||||
videoTracks: {},
|
videoTracks: {},
|
||||||
|
subscriptions: {
|
||||||
|
video: {},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Actions ---
|
// --- Actions ---
|
||||||
|
|
@ -10,19 +13,21 @@ const initialTracksState = {
|
||||||
const TRACK_STARTED = 'TRACK_STARTED';
|
const TRACK_STARTED = 'TRACK_STARTED';
|
||||||
const TRACK_STOPPED = 'TRACK_STOPPED';
|
const TRACK_STOPPED = 'TRACK_STOPPED';
|
||||||
const REMOVE_TRACKS = 'REMOVE_TRACKS';
|
const REMOVE_TRACKS = 'REMOVE_TRACKS';
|
||||||
const UPDATE_TRACKS = 'UPDATE_TRACKS';
|
const UPDATE_SUBSCRIPTIONS = 'UPDATE_SUBSCRIPTIONS';
|
||||||
|
|
||||||
// --- Reducer and helpers --
|
// --- Reducer and helpers --
|
||||||
|
|
||||||
function tracksReducer(prevState, action) {
|
function tracksReducer(prevState, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case TRACK_STARTED:
|
case TRACK_STARTED: {
|
||||||
case TRACK_STOPPED: {
|
const id = getId(action.participant);
|
||||||
const id = action.participant ? getId(action.participant) : null;
|
const screenId = getScreenId(id);
|
||||||
const screenId = action.participant ? getScreenId(id) : null;
|
|
||||||
|
|
||||||
if (action.track.kind === 'audio' && !action.participant?.local) {
|
if (action.track.kind === 'audio') {
|
||||||
// Ignore local audio from mic and screen share
|
if (action.participant?.local) {
|
||||||
|
// Ignore local audio from mic and screen share
|
||||||
|
return prevState;
|
||||||
|
}
|
||||||
const newAudioTracks = {
|
const newAudioTracks = {
|
||||||
[id]: action.participant.tracks.audio,
|
[id]: action.participant.tracks.audio,
|
||||||
};
|
};
|
||||||
|
|
@ -52,8 +57,42 @@ function tracksReducer(prevState, action) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
case TRACK_STOPPED: {
|
||||||
|
const { audioTracks, subscriptions, videoTracks } = prevState;
|
||||||
|
|
||||||
|
const newAudioTracks = { ...audioTracks };
|
||||||
|
const newSubscriptions = { ...subscriptions };
|
||||||
|
const newVideoTracks = { ...videoTracks };
|
||||||
|
|
||||||
|
action.items.forEach(({ participant, track }) => {
|
||||||
|
const id = participant ? getId(participant) : null;
|
||||||
|
const screenId = participant ? getScreenId(id) : null;
|
||||||
|
|
||||||
|
if (track.kind === 'audio') {
|
||||||
|
if (!participant?.local) {
|
||||||
|
// Ignore local audio from mic and screen share
|
||||||
|
newAudioTracks[id] = participant.tracks.audio;
|
||||||
|
if (participant.screen) {
|
||||||
|
newAudioTracks[screenId] = participant.tracks.screenAudio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (track.kind === 'video') {
|
||||||
|
newVideoTracks[id] = participant.tracks.video;
|
||||||
|
if (participant.screen) {
|
||||||
|
newVideoTracks[screenId] = participant.tracks.screenVideo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
audioTracks: newAudioTracks,
|
||||||
|
subscriptions: newSubscriptions,
|
||||||
|
videoTracks: newVideoTracks,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
case REMOVE_TRACKS: {
|
case REMOVE_TRACKS: {
|
||||||
const { audioTracks, videoTracks } = prevState;
|
const { audioTracks, subscriptions, videoTracks } = prevState;
|
||||||
const id = getId(action.participant);
|
const id = getId(action.participant);
|
||||||
const screenId = getScreenId(id);
|
const screenId = getScreenId(id);
|
||||||
|
|
||||||
|
|
@ -64,39 +103,17 @@ function tracksReducer(prevState, action) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
audioTracks,
|
audioTracks,
|
||||||
|
subscriptions,
|
||||||
videoTracks,
|
videoTracks,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case UPDATE_TRACKS: {
|
|
||||||
const { audioTracks, videoTracks } = prevState;
|
|
||||||
const id = getId(action.participant);
|
|
||||||
const screenId = getScreenId(id);
|
|
||||||
|
|
||||||
const newAudioTracks = {
|
|
||||||
...audioTracks,
|
|
||||||
};
|
|
||||||
const newVideoTracks = {
|
|
||||||
...videoTracks,
|
|
||||||
[id]: action.participant.tracks.video,
|
|
||||||
};
|
|
||||||
if (!action.participant.local) {
|
|
||||||
newAudioTracks[id] = action.participant.tracks.audio;
|
|
||||||
}
|
|
||||||
if (action.participant.screen) {
|
|
||||||
newVideoTracks[screenId] = action.participant.tracks.screenVideo;
|
|
||||||
if (!action.participant.local) {
|
|
||||||
newAudioTracks[screenId] = action.participant.tracks.screenAudio;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
delete newAudioTracks[screenId];
|
|
||||||
delete newVideoTracks[screenId];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
case UPDATE_SUBSCRIPTIONS:
|
||||||
return {
|
return {
|
||||||
audioTracks: newAudioTracks,
|
...prevState,
|
||||||
videoTracks: newVideoTracks,
|
subscriptions: action.subscriptions,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
@ -104,9 +121,9 @@ function tracksReducer(prevState, action) {
|
||||||
|
|
||||||
export {
|
export {
|
||||||
initialTracksState,
|
initialTracksState,
|
||||||
|
tracksReducer,
|
||||||
REMOVE_TRACKS,
|
REMOVE_TRACKS,
|
||||||
TRACK_STARTED,
|
TRACK_STARTED,
|
||||||
TRACK_STOPPED,
|
TRACK_STOPPED,
|
||||||
UPDATE_TRACKS,
|
UPDATE_SUBSCRIPTIONS,
|
||||||
tracksReducer,
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ export const useVideoTrack = (participant) => {
|
||||||
!participant.isScreenshare)
|
!participant.isScreenshare)
|
||||||
)
|
)
|
||||||
return null;
|
return null;
|
||||||
return videoTrack?.track;
|
return videoTrack?.persistentTrack;
|
||||||
}, [participant?.id, videoTracks]);
|
}, [participant?.id, videoTracks]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue