Improvements to group calling video requests

This commit is contained in:
Evan Hahn 2022-05-23 17:16:13 +00:00 committed by GitHub
parent 5c72c785a0
commit 3f0ed541f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 95 additions and 32 deletions

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useMemo, useEffect } from 'react';
import { maxBy } from 'lodash';
import { clamp, maxBy } from 'lodash';
import type { VideoFrameSource } from 'ringrtc';
import { Avatar } from './Avatar';
import { CallBackgroundBlur } from './CallBackgroundBlur';
@ -18,11 +18,13 @@ import { CallMode } from '../types/Calling';
import { AvatarColors } from '../types/Colors';
import type { SetRendererCanvasType } from '../state/ducks/calling';
import { useGetCallingFrameBuffer } from '../calling/useGetCallingFrameBuffer';
import { MAX_FRAME_WIDTH } from '../calling/constants';
import { usePageVisibility } from '../hooks/usePageVisibility';
import { missingCaseError } from '../util/missingCaseError';
import { nonRenderedRemoteParticipant } from '../util/ringrtc/nonRenderedRemoteParticipant';
// This value should be kept in sync with the hard-coded CSS height.
// This value should be kept in sync with the hard-coded CSS height. It should also be
// less than `MAX_FRAME_HEIGHT`.
const PIP_VIDEO_HEIGHT_PX = 120;
const NoVideo = ({
@ -110,14 +112,13 @@ export const CallingPipRemoteVideo = ({
if (isPageVisible) {
setGroupCallVideoRequest(
activeCall.remoteParticipants.map(participant => {
const isVisible =
participant === activeGroupCallSpeaker &&
participant.hasRemoteVideo;
if (isVisible) {
if (participant === activeGroupCallSpeaker) {
return {
demuxId: participant.demuxId,
width: Math.floor(
PIP_VIDEO_HEIGHT_PX * participant.videoAspectRatio
width: clamp(
Math.floor(PIP_VIDEO_HEIGHT_PX * participant.videoAspectRatio),
1,
MAX_FRAME_WIDTH
),
height: PIP_VIDEO_HEIGHT_PX,
};

View file

@ -22,7 +22,7 @@ import { ConfirmationDialog } from './ConfirmationDialog';
import { Intl } from './Intl';
import { ContactName } from './conversation/ContactName';
import { useIntersectionObserver } from '../hooks/useIntersectionObserver';
import { MAX_FRAME_SIZE } from '../calling/constants';
import { MAX_FRAME_HEIGHT, MAX_FRAME_WIDTH } from '../calling/constants';
const MAX_TIME_TO_SHOW_STALE_VIDEO_FRAMES = 5000;
const MAX_TIME_TO_SHOW_STALE_SCREENSHARE_FRAMES = 60000;
@ -150,7 +150,8 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
if (
frameWidth < 2 ||
frameHeight < 2 ||
frameWidth * frameHeight > MAX_FRAME_SIZE
frameWidth > MAX_FRAME_WIDTH ||
frameHeight > MAX_FRAME_HEIGHT
) {
return;
}

View file

@ -3,7 +3,7 @@
import React, { useCallback, useState, useMemo, useEffect } from 'react';
import Measure from 'react-measure';
import { takeWhile, chunk, maxBy, flatten, noop } from 'lodash';
import { takeWhile, clamp, chunk, maxBy, flatten, noop } from 'lodash';
import type { VideoFrameSource } from 'ringrtc';
import { GroupCallRemoteParticipant } from './GroupCallRemoteParticipant';
import {
@ -21,9 +21,10 @@ import { useDevicePixelRatio } from '../hooks/useDevicePixelRatio';
import { nonRenderedRemoteParticipant } from '../util/ringrtc/nonRenderedRemoteParticipant';
import { missingCaseError } from '../util/missingCaseError';
import { SECOND } from '../util/durations';
import { filter } from '../util/iterables';
import { filter, join } from '../util/iterables';
import * as setUtil from '../util/setUtil';
import * as log from '../logging/log';
import { MAX_FRAME_HEIGHT, MAX_FRAME_WIDTH } from '../calling/constants';
const MIN_RENDERED_HEIGHT = 180;
const PARTICIPANT_MARGIN = 10;
@ -52,9 +53,9 @@ type PropsType = {
};
enum VideoRequestMode {
Normal,
LowResolution,
NoVideo,
Normal = 'Normal',
LowResolution = 'LowResolution',
NoVideo = 'NoVideo',
}
// This component lays out group call remote participants. It uses a custom layout
@ -298,6 +299,9 @@ export const GroupCallRemoteParticipants: React.FC<PropsType> = ({
);
const videoRequestMode = useVideoRequestMode();
useEffect(() => {
log.info(`Group call now using ${videoRequestMode} video request mode`);
}, [videoRequestMode]);
useEffect(() => {
let videoRequest: Array<GroupCallVideoRequest>;
@ -310,35 +314,44 @@ export const GroupCallRemoteParticipants: React.FC<PropsType> = ({
if (participant.sharingScreen) {
// We want best-resolution video if someone is sharing their screen.
scalar = Math.max(devicePixelRatio, 1);
} else if (participant.hasRemoteVideo) {
scalar = VIDEO_REQUEST_SCALAR;
} else {
scalar = 0;
scalar = VIDEO_REQUEST_SCALAR;
}
return {
demuxId: participant.demuxId,
width: Math.floor(
gridParticipantHeight * participant.videoAspectRatio * scalar
width: clamp(
Math.floor(
gridParticipantHeight * participant.videoAspectRatio * scalar
),
1,
MAX_FRAME_WIDTH
),
height: clamp(
Math.floor(gridParticipantHeight * scalar),
1,
MAX_FRAME_HEIGHT
),
height: Math.floor(gridParticipantHeight * scalar),
};
}),
...overflowedParticipants.map(participant => {
if (
!participant.hasRemoteVideo ||
invisibleDemuxIds.has(participant.demuxId)
) {
if (invisibleDemuxIds.has(participant.demuxId)) {
return nonRenderedRemoteParticipant(participant);
}
return {
demuxId: participant.demuxId,
width: Math.floor(
OVERFLOW_PARTICIPANT_WIDTH * VIDEO_REQUEST_SCALAR
width: clamp(
Math.floor(OVERFLOW_PARTICIPANT_WIDTH * VIDEO_REQUEST_SCALAR),
1,
MAX_FRAME_WIDTH
),
height: Math.floor(
(OVERFLOW_PARTICIPANT_WIDTH / participant.videoAspectRatio) *
VIDEO_REQUEST_SCALAR
height: clamp(
Math.floor(
(OVERFLOW_PARTICIPANT_WIDTH / participant.videoAspectRatio) *
VIDEO_REQUEST_SCALAR
),
1,
MAX_FRAME_HEIGHT
),
};
}),
@ -454,6 +467,12 @@ function useInvisibleParticipants(
[]
);
useEffect(() => {
log.info(
`Invisible demux IDs changed to [${join(invisibleDemuxIds, ',')}]`
);
}, [invisibleDemuxIds]);
useEffect(() => {
const remoteParticipantDemuxIds = new Set<number>(
remoteParticipants.map(r => r.demuxId)