2018-10-30 05:02:23 +00:00
|
|
|
/* @flow */
|
|
|
|
|
2017-08-30 23:58:19 +00:00
|
|
|
import React, { Component } from 'react';
|
|
|
|
|
2018-10-30 05:02:23 +00:00
|
|
|
/**
|
|
|
|
* The type of the React {@code Component} props of {@link Video}.
|
|
|
|
*/
|
|
|
|
type Props = {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* CSS classes to add to the video element.
|
|
|
|
*/
|
|
|
|
className: string,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The value of the id attribute of the video. Used by the torture tests to
|
|
|
|
* locate video elements.
|
|
|
|
*/
|
|
|
|
id: string,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Optional callback to invoke once the video starts playing.
|
|
|
|
*/
|
2019-09-13 13:03:40 +00:00
|
|
|
onVideoPlaying?: Function,
|
2018-10-30 05:02:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The JitsiLocalTrack to display.
|
|
|
|
*/
|
2019-10-08 09:34:25 +00:00
|
|
|
videoTrack: ?Object,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to determine the value of the autoplay attribute of the underlying
|
|
|
|
* video element.
|
|
|
|
*/
|
2020-06-11 20:13:36 +00:00
|
|
|
autoPlay: boolean,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to determine the value of the autoplay attribute of the underlying
|
|
|
|
* video element.
|
|
|
|
*/
|
|
|
|
playsinline: boolean
|
2018-10-30 05:02:23 +00:00
|
|
|
};
|
|
|
|
|
2017-08-30 23:58:19 +00:00
|
|
|
/**
|
|
|
|
* Component that renders a video element for a passed in video track.
|
|
|
|
*
|
|
|
|
* @extends Component
|
|
|
|
*/
|
2018-10-30 05:02:23 +00:00
|
|
|
class Video extends Component<Props> {
|
|
|
|
_videoElement: ?Object;
|
|
|
|
|
2017-08-30 23:58:19 +00:00
|
|
|
/**
|
|
|
|
* Default values for {@code Video} component's properties.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
*/
|
|
|
|
static defaultProps = {
|
|
|
|
className: '',
|
2019-10-08 09:34:25 +00:00
|
|
|
autoPlay: true,
|
2020-06-11 20:13:36 +00:00
|
|
|
id: '',
|
|
|
|
playsinline: true
|
2017-08-30 23:58:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes a new {@code Video} instance.
|
|
|
|
*
|
|
|
|
* @param {Object} props - The read-only properties with which the new
|
|
|
|
* instance is to be initialized.
|
|
|
|
*/
|
2018-10-30 05:02:23 +00:00
|
|
|
constructor(props: Props) {
|
2017-08-30 23:58:19 +00:00
|
|
|
super(props);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The internal reference to the DOM/HTML element intended for
|
2018-06-27 09:43:13 +00:00
|
|
|
* displaying a video.
|
2017-08-30 23:58:19 +00:00
|
|
|
*
|
|
|
|
* @private
|
2018-06-27 09:43:13 +00:00
|
|
|
* @type {HTMLVideoElement}
|
2017-08-30 23:58:19 +00:00
|
|
|
*/
|
|
|
|
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() {
|
2018-10-30 05:02:23 +00:00
|
|
|
if (this._videoElement) {
|
|
|
|
this._videoElement.volume = 0;
|
|
|
|
this._videoElement.onplaying = this._onVideoPlaying;
|
|
|
|
}
|
2017-08-30 23:58:19 +00:00
|
|
|
|
|
|
|
this._attachTrack(this.props.videoTrack);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove any existing associations between the current video track and the
|
|
|
|
* component's video element.
|
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
componentWillUnmount() {
|
|
|
|
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
|
2018-11-08 12:25:02 +00:00
|
|
|
* element, as the lib uses {@code track.attach(videoElement)} instead.
|
2017-08-30 23:58:19 +00:00
|
|
|
*
|
|
|
|
* @inheritdoc
|
2018-11-08 12:25:02 +00:00
|
|
|
* @returns {boolean} - False is always returned to blackbox this component
|
2017-08-30 23:58:19 +00:00
|
|
|
* from React.
|
|
|
|
*/
|
2018-10-30 05:02:23 +00:00
|
|
|
shouldComponentUpdate(nextProps: Props) {
|
2017-08-30 23:58:19 +00:00
|
|
|
const currentJitsiTrack = this.props.videoTrack
|
|
|
|
&& this.props.videoTrack.jitsiTrack;
|
|
|
|
const nextJitsiTrack = nextProps.videoTrack
|
|
|
|
&& nextProps.videoTrack.jitsiTrack;
|
|
|
|
|
|
|
|
if (currentJitsiTrack !== nextJitsiTrack) {
|
|
|
|
this._detachTrack(this.props.videoTrack);
|
|
|
|
this._attachTrack(nextProps.videoTrack);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Renders the video element.
|
|
|
|
*
|
|
|
|
* @override
|
|
|
|
* @returns {ReactElement}
|
|
|
|
*/
|
|
|
|
render() {
|
|
|
|
return (
|
2018-06-27 09:43:13 +00:00
|
|
|
<video
|
2019-10-08 09:34:25 +00:00
|
|
|
autoPlay = { this.props.autoPlay }
|
2018-06-27 09:43:13 +00:00
|
|
|
className = { this.props.className }
|
|
|
|
id = { this.props.id }
|
2020-06-11 20:13:36 +00:00
|
|
|
playsInline = { this.props.playsinline }
|
2018-06-27 09:43:13 +00:00
|
|
|
ref = { this._setVideoElement } />
|
2017-08-30 23:58:19 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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) {
|
|
|
|
if (!videoTrack || !videoTrack.jitsiTrack) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-27 09:43:13 +00:00
|
|
|
videoTrack.jitsiTrack.attach(this._videoElement);
|
2017-08-30 23:58:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes the association to the component's video element from the passed
|
|
|
|
* in redux representation of jitsi video track to stop the track from
|
2018-06-27 09:43:13 +00:00
|
|
|
* rendering.
|
2017-08-30 23:58:19 +00:00
|
|
|
*
|
|
|
|
* @param {Object} videoTrack - The redux representation of the
|
|
|
|
* {@code JitsiLocalTrack}.
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_detachTrack(videoTrack) {
|
2018-06-27 09:43:13 +00:00
|
|
|
if (this._videoElement && videoTrack && videoTrack.jitsiTrack) {
|
2017-08-30 23:58:19 +00:00
|
|
|
videoTrack.jitsiTrack.detach(this._videoElement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-30 05:02:23 +00:00
|
|
|
_onVideoPlaying: () => void;
|
|
|
|
|
2017-08-30 23:58:19 +00:00
|
|
|
/**
|
|
|
|
* Invokes the onvideoplaying callback if defined.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_onVideoPlaying() {
|
|
|
|
if (this.props.onVideoPlaying) {
|
|
|
|
this.props.onVideoPlaying();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-30 05:02:23 +00:00
|
|
|
_setVideoElement: () => void;
|
|
|
|
|
2017-08-30 23:58:19 +00:00
|
|
|
/**
|
|
|
|
* 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) {
|
|
|
|
this._videoElement = element;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default Video;
|