Upgrade to RingRTC v2.8.2 RC.6
This commit is contained in:
parent
4bf5a24efb
commit
b366967ca5
15 changed files with 214 additions and 183 deletions
|
@ -1,64 +1,147 @@
|
|||
// Copyright 2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React, { useRef, useEffect, CSSProperties } from 'react';
|
||||
import React, {
|
||||
useState,
|
||||
useRef,
|
||||
useMemo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
CSSProperties,
|
||||
} from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { noop } from 'lodash';
|
||||
import { CanvasVideoRenderer, VideoFrameSource } from '../types/Calling';
|
||||
import { VideoFrameSource } from '../types/Calling';
|
||||
import { CallBackgroundBlur } from './CallBackgroundBlur';
|
||||
|
||||
interface PropsType {
|
||||
createCanvasVideoRenderer: () => CanvasVideoRenderer;
|
||||
// The max size video frame we'll support (in RGBA)
|
||||
const FRAME_BUFFER_SIZE = 1920 * 1080 * 4;
|
||||
|
||||
interface BasePropsType {
|
||||
demuxId: number;
|
||||
getGroupCallVideoFrameSource: (demuxId: number) => VideoFrameSource;
|
||||
hasRemoteAudio: boolean;
|
||||
hasRemoteVideo: boolean;
|
||||
height: number | string;
|
||||
left: number;
|
||||
top: number;
|
||||
width: number | string;
|
||||
}
|
||||
|
||||
export const GroupCallRemoteParticipant: React.FC<PropsType> = ({
|
||||
createCanvasVideoRenderer,
|
||||
demuxId,
|
||||
getGroupCallVideoFrameSource,
|
||||
hasRemoteAudio,
|
||||
hasRemoteVideo,
|
||||
height,
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
}) => {
|
||||
interface InPipPropsType {
|
||||
isInPip: true;
|
||||
}
|
||||
|
||||
interface NotInPipPropsType {
|
||||
isInPip?: false;
|
||||
width: number;
|
||||
height: number;
|
||||
left: number;
|
||||
top: number;
|
||||
}
|
||||
|
||||
type PropsType = BasePropsType & (InPipPropsType | NotInPipPropsType);
|
||||
|
||||
export const GroupCallRemoteParticipant: React.FC<PropsType> = props => {
|
||||
const {
|
||||
demuxId,
|
||||
getGroupCallVideoFrameSource,
|
||||
hasRemoteAudio,
|
||||
hasRemoteVideo,
|
||||
} = props;
|
||||
|
||||
const [canvasStyles, setCanvasStyles] = useState<CSSProperties>({});
|
||||
|
||||
const remoteVideoRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const canvasVideoRendererRef = useRef(createCanvasVideoRenderer());
|
||||
const rafIdRef = useRef<number | null>(null);
|
||||
const frameBufferRef = useRef<ArrayBuffer>(
|
||||
new ArrayBuffer(FRAME_BUFFER_SIZE)
|
||||
);
|
||||
|
||||
const videoFrameSource = useMemo(
|
||||
() => getGroupCallVideoFrameSource(demuxId),
|
||||
[getGroupCallVideoFrameSource, demuxId]
|
||||
);
|
||||
|
||||
const renderVideoFrame = useCallback(() => {
|
||||
const canvasEl = remoteVideoRef.current;
|
||||
if (!canvasEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const context = canvasEl.getContext('2d');
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
const frameDimensions = videoFrameSource.receiveVideoFrame(
|
||||
frameBufferRef.current
|
||||
);
|
||||
if (!frameDimensions) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [frameWidth, frameHeight] = frameDimensions;
|
||||
canvasEl.width = frameWidth;
|
||||
canvasEl.height = frameHeight;
|
||||
|
||||
context.putImageData(
|
||||
new ImageData(
|
||||
new Uint8ClampedArray(
|
||||
frameBufferRef.current,
|
||||
0,
|
||||
frameWidth * frameHeight * 4
|
||||
),
|
||||
frameWidth,
|
||||
frameHeight
|
||||
),
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
// If our `width` and `height` props don't match the canvas's aspect ratio, we want to
|
||||
// fill the container. This can happen when RingRTC gives us an inaccurate
|
||||
// `videoAspectRatio`, or if the container is an unexpected size.
|
||||
if (frameWidth > frameHeight) {
|
||||
setCanvasStyles({ width: '100%' });
|
||||
} else {
|
||||
setCanvasStyles({ height: '100%' });
|
||||
}
|
||||
}, [videoFrameSource]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasVideoRenderer = canvasVideoRendererRef.current;
|
||||
|
||||
if (hasRemoteVideo) {
|
||||
canvasVideoRenderer.setCanvas(remoteVideoRef);
|
||||
canvasVideoRenderer.enable(getGroupCallVideoFrameSource(demuxId));
|
||||
return () => {
|
||||
canvasVideoRenderer.disable();
|
||||
};
|
||||
if (!hasRemoteVideo) {
|
||||
return noop;
|
||||
}
|
||||
|
||||
canvasVideoRenderer.disable();
|
||||
return noop;
|
||||
}, [hasRemoteVideo, getGroupCallVideoFrameSource, demuxId]);
|
||||
const tick = () => {
|
||||
renderVideoFrame();
|
||||
rafIdRef.current = requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
// If our `width` and `height` props don't match the canvas's aspect ratio, we want to
|
||||
// fill the container. This can happen when RingRTC gives us an inaccurate
|
||||
// `videoAspectRatio`.
|
||||
const canvasStyles: CSSProperties = {};
|
||||
const canvasEl = remoteVideoRef.current;
|
||||
if (hasRemoteVideo && canvasEl) {
|
||||
if (canvasEl.width > canvasEl.height) {
|
||||
canvasStyles.width = '100%';
|
||||
} else {
|
||||
canvasStyles.height = '100%';
|
||||
}
|
||||
rafIdRef.current = requestAnimationFrame(tick);
|
||||
|
||||
return () => {
|
||||
if (rafIdRef.current) {
|
||||
cancelAnimationFrame(rafIdRef.current);
|
||||
rafIdRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [hasRemoteVideo, renderVideoFrame, videoFrameSource]);
|
||||
|
||||
let containerStyles: CSSProperties;
|
||||
|
||||
// TypeScript isn't smart enough to know that `isInPip` by itself disambiguates the
|
||||
// types, so we have to use `props.isInPip` instead.
|
||||
// eslint-disable-next-line react/destructuring-assignment
|
||||
if (props.isInPip) {
|
||||
containerStyles = canvasStyles;
|
||||
} else {
|
||||
const { top, left, width, height } = props;
|
||||
|
||||
containerStyles = {
|
||||
height,
|
||||
left,
|
||||
position: 'absolute',
|
||||
top,
|
||||
width,
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -69,13 +152,7 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = ({
|
|||
'module-ongoing-call__group-call-remote-participant--audio-muted': !hasRemoteAudio,
|
||||
}
|
||||
)}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
width,
|
||||
height,
|
||||
top,
|
||||
left,
|
||||
}}
|
||||
style={containerStyles}
|
||||
>
|
||||
{hasRemoteVideo ? (
|
||||
<canvas
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue