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

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