import React, { Component } from 'react'; import { trackVideoStarted } from '../../tracks'; import { shouldRenderVideoTrack } from '../functions'; import { Video } from './_'; /** * Implements a React {@link Component} that renders video element for a * specific video track. * * @abstract */ export default class AbstractVideoTrack extends Component { /** * Default values for AbstractVideoTrack component's properties. * * @static */ static defaultProps = { /** * Dispatch an action when the video starts playing. */ triggerOnPlayingUpdate: true }; /** * AbstractVideoTrack component's property types. * * @static */ static propTypes = { dispatch: React.PropTypes.func, /** * 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, videoTrack: React.PropTypes.object, 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 }; /** * 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 (