added bandwidth controls to ParticipantProvider
This commit is contained in:
parent
dc2dc63a98
commit
c322312343
|
|
@ -59,6 +59,7 @@ export const SpeakerTile = ({ participant, screenRef }) => {
|
|||
participant={participant}
|
||||
style={style}
|
||||
videoFit={videoFit}
|
||||
showActiveSpeaker={false}
|
||||
onVideoResize={handleNativeAspectRatio}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { useState, useMemo, useEffect, useRef } from 'react';
|
|||
import Tile from '@dailyjs/shared/components/Tile';
|
||||
import { DEFAULT_ASPECT_RATIO } from '@dailyjs/shared/constants';
|
||||
import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider';
|
||||
import usePreferredLayer from '@dailyjs/shared/hooks/usePreferredLayer';
|
||||
import usePreferredLayerByCount from '@dailyjs/shared/hooks/usePreferredLayerByCount';
|
||||
import { useDeepCompareMemo } from 'use-deep-compare';
|
||||
|
||||
/**
|
||||
|
|
@ -106,7 +106,7 @@ export const VideoGrid = React.memo(
|
|||
|
||||
// Optimise performance by reducing video quality
|
||||
// when more participants join (if in SFU mode)
|
||||
usePreferredLayer(allParticipants);
|
||||
usePreferredLayerByCount(allParticipants);
|
||||
|
||||
if (!participants.length) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { DEFAULT_ASPECT_RATIO } from '@dailyjs/shared/constants';
|
|||
import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider';
|
||||
import { useActiveSpeaker } from '@dailyjs/shared/hooks/useActiveSpeaker';
|
||||
import { useCamSubscriptions } from '@dailyjs/shared/hooks/useCamSubscriptions';
|
||||
import usePreferredLayer from '@dailyjs/shared/hooks/usePreferredLayer';
|
||||
import usePreferredLayerByCount from '@dailyjs/shared/hooks/usePreferredLayerByCount';
|
||||
import { ReactComponent as IconArrow } from '@dailyjs/shared/icons/raquo-md.svg';
|
||||
import sortByKey from '@dailyjs/shared/lib/sortByKey';
|
||||
import { useDeepCompareMemo } from 'use-deep-compare';
|
||||
|
|
@ -181,7 +181,7 @@ export const PaginatedVideoGrid = () => {
|
|||
);
|
||||
|
||||
// Set bandwidth layer based on amount of visible participants
|
||||
usePreferredLayer(visibleParticipants);
|
||||
usePreferredLayerByCount(visibleParticipants);
|
||||
|
||||
/**
|
||||
* Handle position updates based on active speaker events
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const Tile = React.memo(
|
|||
mirrored = true,
|
||||
showName = true,
|
||||
showAvatar = true,
|
||||
showActiveSpeaker = true,
|
||||
aspectRatio = DEFAULT_ASPECT_RATIO,
|
||||
onVideoResize,
|
||||
videoFit = 'contain',
|
||||
|
|
@ -22,6 +23,8 @@ export const Tile = React.memo(
|
|||
const videoEl = useRef(null);
|
||||
const [tileAspectRatio, setTileAspectRatio] = useState(aspectRatio);
|
||||
|
||||
const [layer, setLayer] = useState();
|
||||
|
||||
/**
|
||||
* Add optional event listener for resize event so the parent component
|
||||
* can know the video's native aspect ratio.
|
||||
|
|
@ -52,10 +55,26 @@ export const Tile = React.memo(
|
|||
setTileAspectRatio(aspectRatio);
|
||||
}, [aspectRatio, tileAspectRatio]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
typeof rtcpeers === 'undefined' ||
|
||||
rtcpeers?.getCurrentType() !== 'sfu'
|
||||
)
|
||||
return false;
|
||||
|
||||
const i = setInterval(() => {
|
||||
setLayer(
|
||||
rtcpeers.sfu.consumers[`${participant.id}/cam-video`]?._preferredLayer
|
||||
);
|
||||
}, 1500);
|
||||
|
||||
return () => clearInterval(i);
|
||||
}, [participant]);
|
||||
|
||||
const cx = classNames('tile', videoFit, {
|
||||
mirrored,
|
||||
avatar: showAvatar && !videoTrack,
|
||||
active: participant.isActiveSpeaker,
|
||||
active: showActiveSpeaker && participant.isActiveSpeaker,
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
@ -64,7 +83,7 @@ export const Tile = React.memo(
|
|||
{showName && (
|
||||
<div className="name">
|
||||
{participant.isMicMuted && <IconMicMute />}
|
||||
{participant.name}
|
||||
{participant.name} - {layer}
|
||||
</div>
|
||||
)}
|
||||
{videoTrack ? (
|
||||
|
|
@ -92,8 +111,17 @@ export const Tile = React.memo(
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tile.active {
|
||||
.tile.active:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
border: 2px solid var(--primary-default);
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tile .name {
|
||||
|
|
@ -104,10 +132,11 @@ export const Tile = React.memo(
|
|||
left: 0px;
|
||||
z-index: 2;
|
||||
line-height: 1;
|
||||
font-size: 0.875rem;
|
||||
color: white;
|
||||
font-weight: var(--weight-medium);
|
||||
padding: var(--spacing-xxs);
|
||||
text-shadow: 0px 1px 3px rgba(0, 0, 0, 0.35);
|
||||
text-shadow: 0px 1px 3px rgba(0, 0, 0, 0.45);
|
||||
gap: var(--spacing-xxs);
|
||||
}
|
||||
|
||||
|
|
@ -159,6 +188,7 @@ Tile.propTypes = {
|
|||
aspectRatio: PropTypes.number,
|
||||
onVideoResize: PropTypes.func,
|
||||
videoFit: PropTypes.string,
|
||||
showActiveSpeaker: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default Tile;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
/* global rtcpeers */
|
||||
|
||||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
|
|
@ -7,11 +9,16 @@ import React, {
|
|||
useState,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import {
|
||||
useUIState,
|
||||
VIEW_MODE_SPEAKER,
|
||||
} from '@dailyjs/shared/contexts/UIStateProvider';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { sortByKey } from '../lib/sortByKey';
|
||||
|
||||
import { useCallState } from './CallProvider';
|
||||
|
||||
import {
|
||||
initialParticipantsState,
|
||||
isLocalId,
|
||||
|
|
@ -31,6 +38,7 @@ export const ParticipantsProvider = ({ children }) => {
|
|||
participantsReducer,
|
||||
initialParticipantsState
|
||||
);
|
||||
const { viewMode } = useUIState();
|
||||
const [participantMarkedForRemoval, setParticipantMarkedForRemoval] =
|
||||
useState(null);
|
||||
|
||||
|
|
@ -47,6 +55,14 @@ export const ParticipantsProvider = ({ children }) => {
|
|||
*/
|
||||
const participants = useMemo(() => state.participants, [state.participants]);
|
||||
|
||||
/**
|
||||
* Array of participant IDs
|
||||
*/
|
||||
const participantIds = useMemo(
|
||||
() => participants.map((p) => p.id).join(','),
|
||||
[participants]
|
||||
);
|
||||
|
||||
/**
|
||||
* The number of participants, who are not a shared screen
|
||||
* (technically a shared screen counts as a participant, but we shouldn't tell humans)
|
||||
|
|
@ -218,6 +234,40 @@ export const ParticipantsProvider = ({ children }) => {
|
|||
);
|
||||
}, [callObject, handleNewParticipantsState]);
|
||||
|
||||
/**
|
||||
* Adjust video quality from the 3 simulcast layers based
|
||||
* on active speaker status. Note: this currently uses
|
||||
* undocumented internal methods (we'll be adding support
|
||||
* for this into our API soon!)
|
||||
*/
|
||||
const setBandWidthControls = useCallback(() => {
|
||||
if (typeof rtcpeers === 'undefined') return;
|
||||
const sfu = rtcpeers?.soup;
|
||||
const isSFU = rtcpeers?.currentlyPreferred?.typeName?.() === 'sfu';
|
||||
if (!isSFU) return;
|
||||
|
||||
const ids = participantIds.split(',');
|
||||
|
||||
ids.forEach((id) => {
|
||||
if (isLocalId(id)) return;
|
||||
|
||||
// Speaker view settings based on speaker status or pinned user
|
||||
if (viewMode === VIEW_MODE_SPEAKER) {
|
||||
if (currentSpeaker?.id === id) {
|
||||
sfu.setPreferredLayerForTrack(id, 'cam-video', 2);
|
||||
} else {
|
||||
sfu.setPreferredLayerForTrack(id, 'cam-video', 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Note: grid view settings are handled by the grid view component
|
||||
});
|
||||
}, [currentSpeaker?.id, participantIds, viewMode]);
|
||||
|
||||
useEffect(() => {
|
||||
setBandWidthControls();
|
||||
}, [setBandWidthControls]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!callObject) return false;
|
||||
const handleActiveSpeakerChange = ({ activeSpeaker }) => {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { useEffect } from 'react';
|
|||
*
|
||||
* Note: this will have no effect when not in SFU mode
|
||||
*/
|
||||
export const usePreferredLayer = (participants) => {
|
||||
export const usePreferredLayerByCount = (participants) => {
|
||||
/**
|
||||
* Set bandwidth layer based on amount of visible participants
|
||||
*/
|
||||
|
|
@ -40,4 +40,4 @@ export const usePreferredLayer = (participants) => {
|
|||
}, [participants]);
|
||||
};
|
||||
|
||||
export default usePreferredLayer;
|
||||
export default usePreferredLayerByCount;
|
||||
Loading…
Reference in New Issue