您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

Video.js 6.4KB

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