updated Tile & Video to nullify src object
This commit is contained in:
parent
ef545d0480
commit
c9596f14c9
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue