daily-examples/dailyjs/shared/contexts/tracksState.js

147 lines
3.9 KiB
JavaScript

/**
* Track state & reducer
* ---
* All (participant & screen) video and audio tracks indexed on participant ID
* If using manual track subscriptions, we'll also keep a record of those
* and their playing / paused state
*/
import { getId, getScreenId } from './participantsState';
export const initialTracksState = {
audioTracks: {},
videoTracks: {},
};
// --- Actions ---
export const TRACK_STARTED = 'TRACK_STARTED';
export const TRACK_STOPPED = 'TRACK_STOPPED';
export const TRACK_VIDEO_UPDATED = 'TRACK_VIDEO_UPDATED';
export const TRACK_AUDIO_UPDATED = 'TRACK_AUDIO_UPDATED';
export const REMOVE_TRACKS = 'REMOVE_TRACKS';
// --- Reducer and helpers --
export function tracksReducer(prevState, action) {
switch (action.type) {
case TRACK_STARTED: {
const id = getId(action.participant);
const screenId = getScreenId(id);
if (action.track.kind === 'audio') {
if (action.participant?.local) {
// Ignore local audio from mic and screen share
return prevState;
}
const newAudioTracks = {
[id]: action.participant.tracks.audio,
};
if (action.participant.screen) {
newAudioTracks[screenId] = action.participant.tracks.screenAudio;
}
return {
...prevState,
audioTracks: {
...prevState.audioTracks,
...newAudioTracks,
},
};
}
const newVideoTracks = {
[id]: action.participant.tracks.video,
};
if (action.participant.screen) {
newVideoTracks[screenId] = action.participant.tracks.screenVideo;
}
return {
...prevState,
videoTracks: {
...prevState.videoTracks,
...newVideoTracks,
},
};
}
case TRACK_STOPPED: {
const { audioTracks, videoTracks } = prevState;
const newAudioTracks = { ...audioTracks };
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,
videoTracks: newVideoTracks,
};
}
case TRACK_VIDEO_UPDATED: {
const id = getId(action.participant);
if (action.participant?.local) {
// Ignore local audio from mic and screen share
return prevState;
}
const newAudioTracks = {
...prevState.audioTracks,
[id]: action.participant.tracks.audio,
};
return {
...prevState,
audioTracks: newAudioTracks,
};
}
case TRACK_AUDIO_UPDATED: {
const id = getId(action.participant);
const newVideoTracks = {
...prevState.videoTracks,
[id]: action.participant.tracks.video,
};
return {
...prevState,
videoTracks: newVideoTracks,
};
}
case REMOVE_TRACKS: {
const { audioTracks, videoTracks } = prevState;
const id = getId(action.participant);
const screenId = getScreenId(id);
delete audioTracks[id];
delete audioTracks[screenId];
delete videoTracks[id];
delete videoTracks[screenId];
return {
audioTracks,
videoTracks,
};
}
default:
throw new Error();
}
}