2016-10-05 14:36:59 +00:00
|
|
|
import React, { Component } from 'react';
|
|
|
|
|
|
|
|
import { trackVideoStarted } from '../../tracks';
|
|
|
|
|
|
|
|
import { shouldRenderVideoTrack } from '../functions';
|
|
|
|
import { Video } from './_';
|
|
|
|
|
|
|
|
/**
|
2017-06-05 18:00:02 +00:00
|
|
|
* Implements a React {@link Component} that renders video element for a
|
|
|
|
* specific video track.
|
2016-10-05 14:36:59 +00:00
|
|
|
*
|
|
|
|
* @abstract
|
|
|
|
*/
|
2017-06-05 18:00:02 +00:00
|
|
|
export default class AbstractVideoTrack extends Component {
|
2017-07-14 19:22:27 +00:00
|
|
|
/**
|
|
|
|
* Default values for AbstractVideoTrack component's properties.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
*/
|
|
|
|
static defaultProps = {
|
|
|
|
/**
|
|
|
|
* Dispatch an action when the video starts playing.
|
|
|
|
*/
|
|
|
|
triggerOnPlayingUpdate: true
|
|
|
|
};
|
|
|
|
|
2016-12-01 01:52:39 +00:00
|
|
|
/**
|
|
|
|
* AbstractVideoTrack component's property types.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
*/
|
|
|
|
static propTypes = {
|
|
|
|
dispatch: React.PropTypes.func,
|
2017-07-14 19:22:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether or not the store should be updated about the playing status
|
|
|
|
* of the video. Defaults to true. One use case for setting this prop
|
|
|
|
* to false is using multiple locals streams from the same video source,
|
|
|
|
* such as when previewing video. In those cases, the store may have no
|
|
|
|
* need to be updated about the existence or state of the stream.
|
|
|
|
*/
|
|
|
|
triggerOnPlayingUpdate: React.PropTypes.bool,
|
|
|
|
|
2016-12-01 01:52:39 +00:00
|
|
|
videoTrack: React.PropTypes.object,
|
2017-07-14 19:22:27 +00:00
|
|
|
|
2016-12-01 01:52:39 +00:00
|
|
|
waitForVideoStarted: React.PropTypes.bool,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The z-order of the Video of AbstractVideoTrack in the stacking space
|
|
|
|
* of all Videos. For more details, refer to the zOrder property of the
|
|
|
|
* Video class for React Native.
|
|
|
|
*/
|
|
|
|
zOrder: React.PropTypes.number
|
2017-06-02 02:01:50 +00:00
|
|
|
};
|
2016-12-01 01:52:39 +00:00
|
|
|
|
2016-10-05 14:36:59 +00:00
|
|
|
/**
|
|
|
|
* Initializes a new AbstractVideoTrack instance.
|
|
|
|
*
|
|
|
|
* @param {Object} props - The read-only properties with which the new
|
|
|
|
* instance is to be initialized.
|
|
|
|
*/
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
videoTrack: _falsy2null(props.videoTrack)
|
|
|
|
};
|
|
|
|
|
|
|
|
// Bind event handlers so they are only bound once for every instance.
|
|
|
|
this._onVideoPlaying = this._onVideoPlaying.bind(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implements React's {@link Component#componentWillReceiveProps()}.
|
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
* @param {Object} nextProps - The read-only props which this Component will
|
|
|
|
* receive.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
|
const oldValue = this.state.videoTrack;
|
|
|
|
const newValue = _falsy2null(nextProps.videoTrack);
|
|
|
|
|
|
|
|
if (oldValue !== newValue) {
|
|
|
|
this._setVideoTrack(newValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implements React's {@link Component#render()}.
|
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
* @returns {ReactElement}
|
|
|
|
*/
|
|
|
|
render() {
|
|
|
|
const videoTrack = this.state.videoTrack;
|
|
|
|
let render;
|
|
|
|
|
|
|
|
if (this.props.waitForVideoStarted) {
|
|
|
|
// That's the complex case: we have to wait for onPlaying before we
|
|
|
|
// render videoTrack. The complexity comes from the fact that
|
|
|
|
// onPlaying will come after we render videoTrack.
|
|
|
|
if (shouldRenderVideoTrack(videoTrack, true)) {
|
|
|
|
// It appears that onPlaying has come for videoTrack already.
|
|
|
|
// Most probably, another render has already passed through the
|
|
|
|
// else clause bellow already.
|
|
|
|
render = true;
|
|
|
|
} else if (shouldRenderVideoTrack(videoTrack, false)
|
|
|
|
&& !videoTrack.videoStarted) {
|
|
|
|
// XXX Unfortunately, onPlaying has not come for videoTrack yet.
|
|
|
|
// We have to render in order to give onPlaying a chance to
|
|
|
|
// come.
|
|
|
|
render = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// That's the simple case: we don't have to wait for onPlaying
|
|
|
|
// before we render videoTrack
|
|
|
|
render = shouldRenderVideoTrack(videoTrack, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
const stream
|
|
|
|
= render ? videoTrack.jitsiTrack.getOriginalStream() : null;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Video
|
2017-04-05 05:18:41 +00:00
|
|
|
mirror = { videoTrack && videoTrack.mirror }
|
2016-10-05 14:36:59 +00:00
|
|
|
onPlaying = { this._onVideoPlaying }
|
|
|
|
stream = { stream }
|
|
|
|
zOrder = { this.props.zOrder } />
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handler for case when video starts to play.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_onVideoPlaying() {
|
|
|
|
const videoTrack = this.props.videoTrack;
|
|
|
|
|
2017-07-14 19:22:27 +00:00
|
|
|
if (this.props.triggerOnPlayingUpdate
|
|
|
|
&& videoTrack
|
|
|
|
&& !videoTrack.videoStarted) {
|
2016-10-05 14:36:59 +00:00
|
|
|
this.props.dispatch(trackVideoStarted(videoTrack.jitsiTrack));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets a specific video track to be rendered by this instance.
|
|
|
|
*
|
|
|
|
* @param {Track} videoTrack - The video track to be rendered by this
|
|
|
|
* instance.
|
|
|
|
* @protected
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_setVideoTrack(videoTrack) {
|
|
|
|
this.setState({ videoTrack });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns null if a specific value is falsy; otherwise, returns the specified
|
|
|
|
* value.
|
|
|
|
*
|
|
|
|
* @param {*} value - The value to return if it is not falsy.
|
|
|
|
* @returns {*} If the specified value is falsy, null; otherwise, the specified
|
|
|
|
* value.
|
|
|
|
*/
|
|
|
|
function _falsy2null(value) {
|
|
|
|
return value || null;
|
|
|
|
}
|