| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- import React, { Component, ReactEventHandler } from 'react';
-
- import { ITrack } from '../../../tracks/types';
-
- /**
- * The type of the React {@code Component} props of {@link Video}.
- */
- interface IProps {
-
- /**
- * Used to determine the value of the autoplay attribute of the underlying
- * video element.
- */
- autoPlay: boolean;
-
- /**
- * CSS classes to add to the video element.
- */
- className: string;
-
- /**
- * A map of the event handlers for the video HTML element.
- */
- eventHandlers?: {
-
- /**
- * OnAbort event handler.
- */
- onAbort?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnCanPlay event handler.
- */
- onCanPlay?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnCanPlayThrough event handler.
- */
- onCanPlayThrough?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnEmptied event handler.
- */
- onEmptied?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnEnded event handler.
- */
- onEnded?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnError event handler.
- */
- onError?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnLoadStart event handler.
- */
- onLoadStart?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnLoadedData event handler.
- */
- onLoadedData?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnLoadedMetadata event handler.
- */
- onLoadedMetadata?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnPause event handler.
- */
- onPause?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnPlay event handler.
- */
- onPlay?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnPlaying event handler.
- */
- onPlaying?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnRateChange event handler.
- */
- onRateChange?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnStalled event handler.
- */
- onStalled?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnSuspend event handler.
- */
- onSuspend?: ReactEventHandler<HTMLVideoElement>;
-
- /**
- * OnWaiting event handler.
- */
- onWaiting?: ReactEventHandler<HTMLVideoElement>;
- };
-
- /**
- * The value of the id attribute of the video. Used by the torture tests to
- * locate video elements.
- */
- id: string;
-
- /**
- * Used on native.
- */
- mirror?: boolean;
-
- /**
- * The value of the muted attribute for the underlying video element.
- */
- muted?: boolean;
-
- /**
- * Used on native.
- */
- onPlaying?: Function;
-
- /**
- * Used on native.
- */
- onPress?: Function;
-
- /**
- * Optional callback to invoke once the video starts playing.
- */
- onVideoPlaying?: Function;
-
- /**
- * Used to determine the value of the autoplay attribute of the underlying
- * video element.
- */
- playsinline: boolean;
-
- /**
- * Used on native.
- */
- stream?: any;
-
- /**
- * A styles that will be applied on the video element.
- */
- style?: Object;
-
- /**
- * The JitsiLocalTrack to display.
- */
- videoTrack?: Partial<ITrack>;
-
- /**
- * Used on native.
- */
- zOrder?: number;
-
- /**
- * Used on native.
- */
- zoomEnabled?: boolean;
- }
-
- /**
- * Component that renders a video element for a passed in video track.
- *
- * @augments Component
- */
- class Video extends Component<IProps> {
- _videoElement?: HTMLVideoElement | null;
- _mounted: boolean;
-
- /**
- * Default values for {@code Video} component's properties.
- *
- * @static
- */
- static defaultProps = {
- className: '',
- autoPlay: true,
- id: '',
- playsinline: true
- };
-
- /**
- * Initializes a new {@code Video} instance.
- *
- * @param {Object} props - The read-only properties with which the new
- * instance is to be initialized.
- */
- constructor(props: IProps) {
- super(props);
-
- /**
- * The internal reference to the DOM/HTML element intended for
- * displaying a video.
- *
- * @private
- * @type {HTMLVideoElement}
- */
- this._videoElement = null;
-
-
- // Bind event handlers so they are only bound once for every instance.
- this._onVideoPlaying = this._onVideoPlaying.bind(this);
- this._setVideoElement = this._setVideoElement.bind(this);
- }
-
- /**
- * Invokes the library for rendering the video on initial display. Sets the
- * volume level to zero to ensure no sound plays.
- *
- * @inheritdoc
- * @returns {void}
- */
- componentDidMount() {
- this._mounted = true;
-
- if (this._videoElement) {
- this._videoElement.volume = 0;
- this._videoElement.onplaying = this._onVideoPlaying;
- }
-
- this._attachTrack(this.props.videoTrack);
-
- if (this._videoElement && this.props.autoPlay) {
- // Ensure the video gets play() called on it. This may be necessary in the
- // case where the local video container was moved and re-attached, in which
- // case video does not autoplay.
- this._videoElement.play()
- .catch(error => {
- // Prevent uncaught "DOMException: The play() request was interrupted by a new load request"
- // when video playback takes long to start and it starts after the component was unmounted.
- if (this._mounted) {
- throw error;
- }
- });
- }
- }
-
- /**
- * Remove any existing associations between the current video track and the
- * component's video element.
- *
- * @inheritdoc
- * @returns {void}
- */
- componentWillUnmount() {
- this._mounted = false;
- this._detachTrack(this.props.videoTrack);
- }
-
- /**
- * Updates the video display only if a new track is added. This component's
- * updating is blackboxed from React to prevent re-rendering of video
- * element, as the lib uses {@code track.attach(videoElement)} instead.
- *
- * @inheritdoc
- * @returns {boolean} - False is always returned to blackbox this component
- * from React.
- */
- shouldComponentUpdate(nextProps: IProps) {
- const currentJitsiTrack = this.props.videoTrack?.jitsiTrack;
- const nextJitsiTrack = nextProps.videoTrack?.jitsiTrack;
-
- if (currentJitsiTrack !== nextJitsiTrack) {
- this._detachTrack(this.props.videoTrack);
- this._attachTrack(nextProps.videoTrack);
- }
-
- if (this.props.style !== nextProps.style || this.props.className !== nextProps.className) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Renders the video element.
- *
- * @override
- * @returns {ReactElement}
- */
- render() {
- const {
- autoPlay,
- className,
- id,
- muted,
- playsinline,
- style,
- eventHandlers
- } = this.props;
-
- return (
- <video
- autoPlay = { autoPlay }
- className = { className }
- id = { id }
- muted = { muted }
- playsInline = { playsinline }
- ref = { this._setVideoElement }
- style = { style }
- { ...eventHandlers } />
- );
- }
-
- /**
- * Calls into the passed in track to associate the track with the
- * component's video element and render video.
- *
- * @param {Object} videoTrack - The redux representation of the
- * {@code JitsiLocalTrack}.
- * @private
- * @returns {void}
- */
- _attachTrack(videoTrack?: Partial<ITrack>) {
- if (!videoTrack?.jitsiTrack) {
- return;
- }
-
- videoTrack.jitsiTrack.attach(this._videoElement);
- }
-
- /**
- * Removes the association to the component's video element from the passed
- * in redux representation of jitsi video track to stop the track from
- * rendering.
- *
- * @param {Object} videoTrack - The redux representation of the
- * {@code JitsiLocalTrack}.
- * @private
- * @returns {void}
- */
- _detachTrack(videoTrack?: Partial<ITrack>) {
- if (this._videoElement && videoTrack && videoTrack.jitsiTrack) {
- videoTrack.jitsiTrack.detach(this._videoElement);
- }
- }
-
- /**
- * Invokes the onvideoplaying callback if defined.
- *
- * @private
- * @returns {void}
- */
- _onVideoPlaying() {
- if (this.props.onVideoPlaying) {
- this.props.onVideoPlaying();
- }
- }
-
- /**
- * Sets an instance variable for the component's video element so it can be
- * referenced later for attaching and detaching a JitsiLocalTrack.
- *
- * @param {Object} element - DOM element for the component's video display.
- * @private
- * @returns {void}
- */
- _setVideoElement(element: HTMLVideoElement | null) {
- this._videoElement = element;
- }
- }
-
- export default Video;
|