You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VideoTrack.js 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import React from 'react';
  2. import { connect } from 'react-redux';
  3. import AbstractVideoTrack from '../AbstractVideoTrack';
  4. /**
  5. * Component that renders a video element for a passed in video track.
  6. *
  7. * @extends AbstractVideoTrack
  8. */
  9. class VideoTrack extends AbstractVideoTrack {
  10. /**
  11. * Default values for {@code VideoTrack} component's properties.
  12. *
  13. * @static
  14. */
  15. static defaultProps = {
  16. ...AbstractVideoTrack.defaultProps,
  17. className: '',
  18. id: ''
  19. };
  20. /**
  21. * {@code VideoTrack} component's property types.
  22. *
  23. * @static
  24. */
  25. static propTypes = {
  26. ...AbstractVideoTrack.propTypes,
  27. /**
  28. * CSS classes to add to the video element.
  29. */
  30. className: React.PropTypes.string,
  31. /**
  32. * The value of the id attribute of the video. Used by the torture tests
  33. * to locate video elements.
  34. */
  35. id: React.PropTypes.string
  36. };
  37. /**
  38. * Initializes a new VideoTrack instance.
  39. *
  40. * @param {Object} props - The read-only properties with which the new
  41. * instance is to be initialized.
  42. */
  43. constructor(props) {
  44. super(props);
  45. /**
  46. * The internal reference to the DOM/HTML element intended for
  47. * displaying a video. This element may be an HTML video element or a
  48. * temasys video object.
  49. *
  50. * @private
  51. * @type {HTMLVideoElement|Object}
  52. */
  53. this._videoElement = null;
  54. // Bind event handlers so they are only bound once for every instance.
  55. this._setVideoElement = this._setVideoElement.bind(this);
  56. }
  57. /**
  58. * Invokes the library for rendering the video on initial display. Sets the
  59. * volume level to zero to ensure no sound plays.
  60. *
  61. * @inheritdoc
  62. * @returns {void}
  63. */
  64. componentDidMount() {
  65. // Add these attributes directly onto the video element so temasys can
  66. // use them when converting the video to an object.
  67. this._videoElement.volume = 0;
  68. this._videoElement.onplaying = this._onVideoPlaying;
  69. this._attachTrack(this.props.videoTrack);
  70. }
  71. /**
  72. * Remove any existing associations between the current video track and the
  73. * component's video element.
  74. *
  75. * @inheritdoc
  76. * @returns {void}
  77. */
  78. componentWillUnmount() {
  79. this._detachTrack(this.props.videoTrack);
  80. }
  81. /**
  82. * Updates the video display only if a new track is added. This component's
  83. * updating is blackboxed from React to prevent re-rendering of video
  84. * element, as the lib uses track.attach(videoElement) instead. Also,
  85. * re-rendering cannot be used with temasys, which replaces video elements
  86. * with an object.
  87. *
  88. * @inheritdoc
  89. * @returns {boolean} - False is always returned to blackbox this component.
  90. * from React.
  91. */
  92. shouldComponentUpdate(nextProps) {
  93. const currentJitsiTrack = this.props.videoTrack
  94. && this.props.videoTrack.jitsiTrack;
  95. const nextJitsiTrack = nextProps.videoTrack
  96. && nextProps.videoTrack.jitsiTrack;
  97. if (currentJitsiTrack !== nextJitsiTrack) {
  98. this._detachTrack(this.props.videoTrack);
  99. this._attachTrack(nextProps.videoTrack);
  100. }
  101. return false;
  102. }
  103. /**
  104. * Renders the video element.
  105. *
  106. * @override
  107. * @returns {ReactElement}
  108. */
  109. render() {
  110. // The wrapping div is necessary because temasys will replace the video
  111. // with an object but react will keep expecting the video element. The
  112. // div gives a constant element for react to keep track of.
  113. return (
  114. <div>
  115. <video
  116. autoPlay = { true }
  117. className = { this.props.className }
  118. id = { this.props.id }
  119. ref = { this._setVideoElement } />
  120. </div>
  121. );
  122. }
  123. /**
  124. * Calls into the passed in track to associate the track with the
  125. * component's video element and render video.
  126. *
  127. * @param {Object} videoTrack - The redux representation of the
  128. * {@code JitsiLocalTrack}.
  129. * @private
  130. * @returns {void}
  131. */
  132. _attachTrack(videoTrack) {
  133. if (!videoTrack || !videoTrack.jitsiTrack) {
  134. return;
  135. }
  136. const updatedVideoElement
  137. = videoTrack.jitsiTrack.attach(this._videoElement);
  138. // Sets the instance variable for the video element again as the element
  139. // maybe have been replaced with a new object by temasys.
  140. this._setVideoElement(updatedVideoElement);
  141. }
  142. /**
  143. * Removes the association to the component's video element from the passed
  144. * in redux representation of jitsi video track to stop the track from
  145. * rendering. With temasys, the video element must still be visible for
  146. * detaching to complete.
  147. *
  148. * @param {Object} videoTrack - The redux representation of the
  149. * {@code JitsiLocalTrack}.
  150. * @private
  151. * @returns {void}
  152. */
  153. _detachTrack(videoTrack) {
  154. // Detach the video element from the track only if it has already
  155. // been attached. This accounts for a special case with temasys
  156. // where if detach is being called before attach, the video
  157. // element is converted to Object without updating this
  158. // component's reference to the video element.
  159. if (this._videoElement
  160. && videoTrack
  161. && videoTrack.jitsiTrack
  162. && videoTrack.jitsiTrack.containers.includes(this._videoElement)) {
  163. videoTrack.jitsiTrack.detach(this._videoElement);
  164. }
  165. }
  166. /**
  167. * Sets an instance variable for the component's video element so it can be
  168. * referenced later for attaching and detaching a JitsiLocalTrack.
  169. *
  170. * @param {Object} element - DOM element for the component's video display.
  171. * @private
  172. * @returns {void}
  173. */
  174. _setVideoElement(element) {
  175. this._videoElement = element;
  176. }
  177. }
  178. export default connect()(VideoTrack);