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 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import React from 'react';
  2. import { Animated } from 'react-native';
  3. import { connect } from 'react-redux';
  4. import { AbstractVideoTrack } from '../AbstractVideoTrack';
  5. import { styles } from './styles';
  6. /**
  7. * Component that renders video element for a specified video track.
  8. *
  9. * @extends AbstractVideoTrack
  10. */
  11. class VideoTrack extends AbstractVideoTrack {
  12. /**
  13. * Initializes a new VideoTrack instance.
  14. *
  15. * @param {Object} props - The read-only properties with which the new
  16. * instance is to be initialized.
  17. */
  18. constructor(props) {
  19. super(props);
  20. /**
  21. * Reference to currently running animation if any.
  22. *
  23. * @private
  24. */
  25. this._animation = null;
  26. /**
  27. * Extend Component's state with additional animation-related vars.
  28. *
  29. * @type {Object}
  30. */
  31. this.state = {
  32. ...this.state,
  33. fade: new Animated.Value(1),
  34. flip: new Animated.Value(1)
  35. };
  36. }
  37. /**
  38. * Renders video element with animation.
  39. *
  40. * @override
  41. * @returns {ReactElement}
  42. */
  43. render() {
  44. return (
  45. <Animated.View
  46. style = { [ styles.video, this._getAnimationStyles() ] }>
  47. { super.render() }
  48. </Animated.View>
  49. );
  50. }
  51. /**
  52. * Animates setting a new video track to be rendered by this instance.
  53. *
  54. * @param {Track} oldValue - The old video track rendered by this instance.
  55. * @param {Track} newValue - The new video track to be rendered by this
  56. * instance.
  57. * @private
  58. * @returns {Promise}
  59. */
  60. _animateSetVideoTrack(oldValue, newValue) {
  61. // If we're in the middle of an animation and a new animation is about
  62. // to start, stop the previous one first.
  63. if (this._animation) {
  64. this._animation.stop();
  65. this._animation = null;
  66. this.state.fade.setValue(1);
  67. this.state.flip.setValue(1);
  68. }
  69. // If we're switching between two local video tracks, that actually
  70. // means we're switching local cameras, so we'll use a flip animation.
  71. // Otherwise, we'll use fade animation.
  72. const animation
  73. = oldValue && newValue && oldValue.local && newValue.local
  74. ? 'flip'
  75. : 'fade';
  76. return this._animateVideoTrack(animation, 0)
  77. .then(() => {
  78. super._setVideoTrack(newValue);
  79. return this._animateVideoTrack(animation, 1);
  80. })
  81. .catch(() => {
  82. console.log('Animation was stopped');
  83. });
  84. }
  85. /**
  86. * Animates the display of the state videoTrack.
  87. *
  88. * @param {string} animatedValue - The name of the state property which
  89. * specifies the Animated.Value to be animated.
  90. * @param {number} toValue - The value to which the specified animatedValue
  91. * is to be animated.
  92. * @private
  93. * @returns {Promise}
  94. */
  95. _animateVideoTrack(animatedValue, toValue) {
  96. return new Promise((resolve, reject) => {
  97. this._animation
  98. = Animated.timing(this.state[animatedValue], { toValue });
  99. this._animation.start(result => {
  100. this._animation = null;
  101. result.finished ? resolve() : reject();
  102. });
  103. });
  104. }
  105. /**
  106. * Returns animation styles for Animated.View.
  107. *
  108. * @private
  109. * @returns {Object}
  110. */
  111. _getAnimationStyles() {
  112. return {
  113. opacity: this.state.fade,
  114. transform: [ {
  115. rotateY: this.state.flip.interpolate({
  116. inputRange: [ 0, 1 ],
  117. outputRange: [ '90deg', '0deg' ]
  118. })
  119. } ]
  120. };
  121. }
  122. // eslint-disable-next-line valid-jsdoc
  123. /**
  124. * @inheritdoc
  125. *
  126. * Animate the setting of the video track to be rendered by this instance.
  127. */
  128. _setVideoTrack(videoTrack) {
  129. // If JitsiTrack instance didn't change, that means some other track's
  130. // props were changed and we don't need to animate.
  131. const oldValue = this.state.videoTrack;
  132. const oldJitsiTrack = oldValue ? oldValue.jitsiTrack : null;
  133. const newValue = videoTrack;
  134. const newJitsiTrack = newValue ? newValue.jitsiTrack : null;
  135. if (oldJitsiTrack === newJitsiTrack) {
  136. super._setVideoTrack(newValue);
  137. } else {
  138. this._animateSetVideoTrack(oldValue, newValue);
  139. }
  140. }
  141. }
  142. /**
  143. * VideoTrack component's property types.
  144. *
  145. * @static
  146. */
  147. VideoTrack.propTypes = AbstractVideoTrack.propTypes;
  148. export default connect()(VideoTrack);