updated Tile & Video to nullify src object

This commit is contained in:
Jon 2021-07-28 15:35:01 +01:00
parent ef545d0480
commit c9596f14c9
3 changed files with 74 additions and 22 deletions

View File

@ -1,5 +1,11 @@
/**
* Audio
* ---
* When working with audio elements it's very important to avoid mutating
* the DOM elements as much as possible to avoid audio pops and crackles.
* This component addresses to known browser quirks; Safari autoplay
* and Chrome's maximum media elements. On Chrome we add all audio tracks
* into into a single audio node using the CombinedAudioTrack component
*/
import React, { useEffect, useMemo } from 'react';
import { useTracks } from '@dailyjs/shared/contexts/TracksProvider';

View File

@ -1,4 +1,4 @@
import React, { useRef } from 'react';
import React, { useEffect, useRef } from 'react';
import useVideoTrack from '@dailyjs/shared/hooks/useVideoTrack';
import { ReactComponent as IconMicMute } from '@dailyjs/shared/icons/mic-off-sm.svg';
import classNames from 'classnames';
@ -14,11 +14,36 @@ export const Tile = React.memo(
showName = true,
showAvatar = true,
aspectRatio = DEFAULT_ASPECT_RATIO,
onVideoResize,
...props
}) => {
const videoTrack = useVideoTrack(participant);
const videoEl = useRef(null);
/**
* Add optional event listener for resize event so the parent component
* can know the video's native aspect ratio.
*/
useEffect(() => {
const video = videoEl.current;
if (!onVideoResize || !video) return false;
const handleResize = () => {
if (!video) return;
const width = video?.videoWidth;
const height = video?.videoHeight;
if (width && height) {
// Return the video's aspect ratio to the parent's handler
onVideoResize(width / height);
}
};
handleResize();
video?.addEventListener('resize', handleResize);
return () => video?.removeEventListener('resize', handleResize);
}, [onVideoResize, videoEl, participant]);
const cx = classNames('tile', {
mirrored,
avatar: showAvatar && !videoTrack,
@ -35,7 +60,11 @@ export const Tile = React.memo(
</div>
)}
{videoTrack ? (
<Video ref={videoEl} videoTrack={videoTrack} />
<Video
ref={videoEl}
participantId={participant?.id}
videoTrack={videoTrack}
/>
) : (
showAvatar && (
<div className="avatar">
@ -122,6 +151,7 @@ Tile.propTypes = {
showName: PropTypes.bool,
showAvatar: PropTypes.bool,
aspectRatio: PropTypes.number,
onVideoResize: PropTypes.func,
};
export default Tile;

View File

@ -1,31 +1,46 @@
import React, { forwardRef, memo, useEffect } from 'react';
import React, { useMemo, forwardRef, memo, useEffect } from 'react';
import Bowser from 'bowser';
import PropTypes from 'prop-types';
import { shallowEqualObjects } from 'shallow-equal';
export const Video = memo(
forwardRef(({ videoTrack, ...rest }, videoEl) => {
forwardRef(({ participantId, videoTrack, ...rest }, videoEl) => {
// See: https://bugs.chromium.org/p/chromium/issues/detail?id=1232649
const isChrome92 = useMemo(() => {
const { browser, platform, os } = Bowser.parse(navigator.userAgent);
return (
browser.name === 'Chrome' &&
parseInt(browser.version, 10) >= 92 &&
(platform.type === 'desktop' || os.name === 'Android')
);
}, []);
/**
* Effect: Umount
* Note: nullify src to ensure media object is not counted
*/
useEffect(() => {
const video = videoEl.current;
if (!video) return false;
// clean up when video renders for different participant
video.srcObject = null;
if (isChrome92) video.load();
return () => {
// clean up when unmounted
video.srcObject = null;
if (isChrome92) video.load();
};
}, [videoEl, isChrome92, participantId]);
/**
* Effect: mount source
*/
useEffect(() => {
if (!videoEl?.current) return;
// eslint-disable-next-line no-param-reassign
videoEl.current.srcObject = new MediaStream([videoTrack]);
}, [videoEl, videoTrack]);
/**
* Effect: unmount
*/
useEffect(
() => () => {
if (videoEl?.current?.srcObject) {
videoEl.current.srcObject.getVideoTracks().forEach((t) => t.stop());
// eslint-disable-next-line no-param-reassign
videoEl.current.srcObject = null;
}
},
[videoEl]
);
const video = videoEl.current;
if (!video || !videoTrack) return;
video.srcObject = new MediaStream([videoTrack]);
if (isChrome92) video.load();
}, [videoEl, isChrome92, videoTrack]);
return <video autoPlay muted playsInline ref={videoEl} {...rest} />;
}),
@ -35,6 +50,7 @@ export const Video = memo(
Video.propTypes = {
videoTrack: PropTypes.any,
mirrored: PropTypes.bool,
participantId: PropTypes.string,
};
export default Video;