jiti-meet/react/features/base/tracks/reducer.ts

197 lines
5.8 KiB
TypeScript
Raw Normal View History

import { MediaType } from '../media/constants';
import { PARTICIPANT_ID_CHANGED } from '../participants/actionTypes';
import ReducerRegistry from '../redux/ReducerRegistry';
import { set } from '../redux/functions';
import {
2019-11-25 12:31:08 +00:00
SET_NO_SRC_DATA_NOTIFICATION_UID,
TRACK_ADDED,
TRACK_CREATE_CANCELED,
TRACK_CREATE_ERROR,
2019-06-12 21:05:41 +00:00
TRACK_NO_DATA_FROM_SOURCE,
TRACK_REMOVED,
TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT,
TRACK_UPDATED,
TRACK_WILL_CREATE
} from './actionTypes';
export interface ITrack {
isReceivingData: boolean;
jitsiTrack: any;
lastMediaEvent?: string;
local: boolean;
mediaType: MediaType;
mirror: boolean;
muted: boolean;
noDataFromSourceNotificationInfo?: {
timeout?: number;
uid?: string;
};
participantId: string;
2022-08-11 18:56:01 +00:00
streamingStatus?: string;
videoStarted: boolean;
videoType?: string | null;
}
/**
2021-11-26 08:11:23 +00:00
* Track type.
*
* @typedef {object} Track
* @property {JitsiLocalTrack|JitsiRemoteTrack} jitsiTrack - The associated
* {@code JitsiTrack} instance. Optional for local tracks if those are still
2021-11-26 08:11:23 +00:00
* being created (ie {@code getUserMedia} is still in progress).
* @property {Promise} [gumProcess] - If a local track is still being created,
* it will have no {@code JitsiTrack}, but a {@code gumProcess} set to a
* {@code Promise} with and extra {@code cancel()}.
* @property {boolean} local=false - If the track is local.
* @property {MEDIA_TYPE} mediaType=false - The media type of the track.
2017-04-05 05:18:41 +00:00
* @property {boolean} mirror=false - The indicator which determines whether the
* display/rendering of the track should be mirrored. It only makes sense in the
* context of video (at least at the time of this writing).
* @property {boolean} muted=false - If the track is muted.
* @property {(string|undefined)} participantId - The ID of the participant whom
* the track belongs to.
* @property {boolean} videoStarted=false - If the video track has already
* started to play.
* @property {(VIDEO_TYPE|undefined)} videoType - The type of video track if
* any.
*/
/**
* Reducer function for a single track.
*
* @param {Track|undefined} state - Track to be modified.
* @param {Object} action - Action object.
* @param {string} action.type - Type of action.
* @param {string} action.name - Name of last media event.
* @param {string} action.newValue - New participant ID value (in this
* particular case).
* @param {string} action.oldValue - Old participant ID value (in this
* particular case).
* @param {Track} action.track - Information about track to be changed.
* @param {Participant} action.participant - Information about participant.
* @returns {Track|undefined}
*/
function track(state: ITrack, action: any) {
switch (action.type) {
case PARTICIPANT_ID_CHANGED:
if (state.participantId === action.oldValue) {
return {
...state,
participantId: action.newValue
};
}
break;
case TRACK_UPDATED: {
const t = action.track;
if (state.jitsiTrack === t.jitsiTrack) {
// Make sure that there's an actual update in order to reduce the
// risk of unnecessary React Component renders.
for (const p in t) {
// @ts-ignore
if (state[p] !== t[p]) {
// There's an actual update.
return {
...state,
...t
};
}
}
}
break;
}
case TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT: {
const t = action.track;
if (state.jitsiTrack === t) {
if (state.lastMediaEvent !== action.name) {
return {
...state,
lastMediaEvent: action.name
};
}
}
break;
}
2019-06-12 21:05:41 +00:00
case TRACK_NO_DATA_FROM_SOURCE: {
const t = action.track;
if (state.jitsiTrack === t.jitsiTrack) {
const isReceivingData = t.jitsiTrack.isReceivingData();
if (state.isReceivingData !== isReceivingData) {
return {
...state,
isReceivingData
};
}
}
break;
}
}
return state;
}
export type ITracksState = ITrack[];
/**
2021-11-04 21:10:43 +00:00
* Listen for actions that mutate (e.g. Add, remove) local and remote tracks.
*/
2022-09-05 09:05:07 +00:00
ReducerRegistry.register<ITracksState>('features/base/tracks', (state = [], action): ITracksState => {
switch (action.type) {
case PARTICIPANT_ID_CHANGED:
2019-06-12 21:05:41 +00:00
case TRACK_NO_DATA_FROM_SOURCE:
case TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT:
case TRACK_UPDATED:
return state.map((t: ITrack) => track(t, action));
case TRACK_ADDED: {
let withoutTrackStub = state;
if (action.track.local) {
withoutTrackStub
= state.filter(
(t: ITrack) => !t.local || t.mediaType !== action.track.mediaType);
}
return [ ...withoutTrackStub, action.track ];
}
case TRACK_CREATE_CANCELED:
case TRACK_CREATE_ERROR: {
return state.filter((t: ITrack) => !t.local || t.mediaType !== action.trackType);
}
case TRACK_REMOVED:
return state.filter((t: ITrack) => t.jitsiTrack !== action.track.jitsiTrack);
case TRACK_WILL_CREATE:
return [ ...state, action.track ];
default:
return state;
}
});
export interface INoSrcDataState {
noSrcDataNotificationUid?: string | number;
}
/**
2021-11-04 21:10:43 +00:00
* Listen for actions that mutate the no-src-data state, like the current notification id.
*/
2022-09-05 09:05:07 +00:00
ReducerRegistry.register<INoSrcDataState>('features/base/no-src-data', (state = {}, action): INoSrcDataState => {
switch (action.type) {
2019-11-25 12:31:08 +00:00
case SET_NO_SRC_DATA_NOTIFICATION_UID:
2019-11-22 14:02:59 +00:00
return set(state, 'noSrcDataNotificationUid', action.uid);
default:
return state;
}
});