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.

VirtualBackgroundPreview.js 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // @flow
  2. import Spinner from '@atlaskit/spinner';
  3. import React, { PureComponent } from 'react';
  4. import { translate } from '../../base/i18n';
  5. import Video from '../../base/media/components/Video';
  6. import { connect, equals } from '../../base/redux';
  7. import { getCurrentCameraDeviceId } from '../../base/settings';
  8. import { createLocalTracksF } from '../../base/tracks/functions';
  9. import { toggleBackgroundEffect } from '../actions';
  10. const videoClassName = 'video-preview-video flipVideoX';
  11. /**
  12. * The type of the React {@code PureComponent} props of {@link VirtualBackgroundPreview}.
  13. */
  14. export type Props = {
  15. /**
  16. * The deviceId of the camera device currently being used.
  17. */
  18. _currentCameraDeviceId: string,
  19. /**
  20. * The redux {@code dispatch} function.
  21. */
  22. dispatch: Function,
  23. /**
  24. * Represents the virtual background setted options.
  25. */
  26. options: Object,
  27. /**
  28. * Invoked to obtain translated strings.
  29. */
  30. t: Function
  31. };
  32. /**
  33. * The type of the React {@code Component} state of {@link VirtualBackgroundPreview}.
  34. */
  35. type State = {
  36. /**
  37. * Loader activated on setting virtual background.
  38. */
  39. loading: boolean,
  40. /**
  41. * Activate the selected device camera only.
  42. */
  43. jitsiTrack: Object
  44. };
  45. /**
  46. * Implements a React {@link PureComponent} which displays the virtual
  47. * background preview.
  48. *
  49. * @extends PureComponent
  50. */
  51. class VirtualBackgroundPreview extends PureComponent<Props, State> {
  52. _componentWasUnmounted: boolean;
  53. /**
  54. * Initializes a new {@code VirtualBackgroundPreview} instance.
  55. *
  56. * @param {Object} props - The read-only properties with which the new
  57. * instance is to be initialized.
  58. */
  59. constructor(props) {
  60. super(props);
  61. this.state = {
  62. loading: false,
  63. jitsiTrack: null
  64. };
  65. }
  66. /**
  67. * Creates and updates the track data.
  68. *
  69. * @returns {void}
  70. */
  71. async _setTracks() {
  72. const [ jitsiTrack ] = await createLocalTracksF({
  73. cameraDeviceId: this.props._currentCameraDeviceId,
  74. devices: [ 'video' ]
  75. });
  76. // In case the component gets unmounted before the tracks are created
  77. // avoid a leak by not setting the state
  78. if (this._componentWasUnmounted) {
  79. return;
  80. }
  81. this.setState({
  82. jitsiTrack
  83. });
  84. }
  85. /**
  86. * Apply background effect on video preview.
  87. *
  88. * @returns {Promise}
  89. */
  90. async _applyBackgroundEffect() {
  91. this.setState({ loading: true });
  92. await this.props.dispatch(toggleBackgroundEffect(this.props.options, this.state.jitsiTrack));
  93. this.setState({ loading: false });
  94. }
  95. /**
  96. * Apply video preview loader.
  97. *
  98. * @returns {Promise}
  99. */
  100. _loadVideoPreview() {
  101. return (
  102. <div className = 'video-preview-loader'>
  103. <Spinner
  104. invertColor = { true }
  105. isCompleting = { false }
  106. size = { 'large' } />
  107. </div>
  108. );
  109. }
  110. /**
  111. * Renders a preview entry.
  112. *
  113. * @param {Object} data - The track data.
  114. * @returns {React$Node}
  115. */
  116. _renderPreviewEntry(data) {
  117. const { t } = this.props;
  118. const className = 'video-background-preview-entry';
  119. if (this.state.loading) {
  120. return this._loadVideoPreview();
  121. }
  122. if (!data) {
  123. return (
  124. <div
  125. className = { className }
  126. video-preview-container = { true }>
  127. <div className = 'video-preview-error'>{t('deviceSelection.previewUnavailable')}</div>
  128. </div>
  129. );
  130. }
  131. const props: Object = {
  132. className
  133. };
  134. return (
  135. <div { ...props }>
  136. <Video
  137. className = { videoClassName }
  138. playsinline = { true }
  139. videoTrack = {{ jitsiTrack: data }} />
  140. </div>
  141. );
  142. }
  143. /**
  144. * Implements React's {@link Component#componentDidMount}.
  145. *
  146. * @inheritdoc
  147. */
  148. componentDidMount() {
  149. this._setTracks();
  150. }
  151. /**
  152. * Implements React's {@link Component#componentWillUnmount}.
  153. *
  154. * @inheritdoc
  155. */
  156. componentWillUnmount() {
  157. this._componentWasUnmounted = true;
  158. }
  159. /**
  160. * Implements React's {@link Component#componentDidUpdate}.
  161. *
  162. * @inheritdoc
  163. */
  164. async componentDidUpdate(prevProps) {
  165. if (!equals(this.props._currentCameraDeviceId, prevProps._currentCameraDeviceId)) {
  166. this._setTracks();
  167. }
  168. if (!equals(this.props.options, prevProps.options)) {
  169. this._applyBackgroundEffect();
  170. }
  171. }
  172. /**
  173. * Implements React's {@link Component#render}.
  174. *
  175. * @inheritdoc
  176. */
  177. render() {
  178. const { jitsiTrack } = this.state;
  179. return jitsiTrack
  180. ? <div className = 'video-preview'>{this._renderPreviewEntry(jitsiTrack)}</div>
  181. : <div className = 'video-preview-loader'>{this._loadVideoPreview()}</div>
  182. ;
  183. }
  184. }
  185. /**
  186. * Maps (parts of) the redux state to the associated props for the
  187. * {@code VirtualBackgroundPreview} component.
  188. *
  189. * @param {Object} state - The Redux state.
  190. * @private
  191. * @returns {{Props}}
  192. */
  193. function _mapStateToProps(state): Object {
  194. return {
  195. _currentCameraDeviceId: getCurrentCameraDeviceId(state)
  196. };
  197. }
  198. export default translate(connect(_mapStateToProps)(VirtualBackgroundPreview));