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.

Thumbnail.js 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import React, { Component } from 'react';
  2. import { connect } from 'react-redux';
  3. import {
  4. Audio,
  5. MEDIA_TYPE
  6. } from '../../base/media';
  7. import {
  8. PARTICIPANT_ROLE,
  9. pinParticipant
  10. } from '../../base/participants';
  11. import { Container } from '../../base/react';
  12. import { getTrackByMediaTypeAndParticipant } from '../../base/tracks';
  13. import { ParticipantView } from '../../conference';
  14. import {
  15. AudioMutedIndicator,
  16. DominantSpeakerIndicator,
  17. ModeratorIndicator,
  18. styles,
  19. VideoMutedIndicator
  20. } from './_';
  21. /**
  22. * React component for video thumbnail.
  23. * @extends Component
  24. */
  25. class Thumbnail extends Component {
  26. /**
  27. * Thumbnail component's property types.
  28. *
  29. * @static
  30. */
  31. static propTypes = {
  32. audioTrack: React.PropTypes.object,
  33. dispatch: React.PropTypes.func,
  34. largeVideo: React.PropTypes.object,
  35. participant: React.PropTypes.object,
  36. videoTrack: React.PropTypes.object
  37. }
  38. /**
  39. * Initializes new Video Thumbnail component.
  40. *
  41. * @param {Object} props - Component props.
  42. */
  43. constructor(props) {
  44. super(props);
  45. // Bind event handlers so they are only bound once for every instance.
  46. this._onClick = this._onClick.bind(this);
  47. }
  48. /**
  49. * Handles click/tap event on the thumbnail.
  50. *
  51. * @returns {void}
  52. */
  53. _onClick() {
  54. const { dispatch, participant } = this.props;
  55. // TODO The following currently ignores interfaceConfig.filmStripOnly.
  56. dispatch(pinParticipant(participant.pinned ? null : participant.id));
  57. }
  58. /**
  59. * Implements React's {@link Component#render()}.
  60. *
  61. * @inheritdoc
  62. * @returns {ReactElement}
  63. */
  64. render() {
  65. const {
  66. audioTrack,
  67. largeVideo,
  68. participant,
  69. videoTrack
  70. } = this.props;
  71. let style = styles.thumbnail;
  72. if (participant.pinned) {
  73. style = {
  74. ...style,
  75. ...styles.thumbnailPinned
  76. };
  77. }
  78. const thumbToolbarStyle = styles.thumbnailIndicatorContainer;
  79. // We don't render audio in any of the following:
  80. // 1. The audio (source) is muted. There's no practical reason (that we
  81. // know of, anyway) why we'd want to render it given that it's
  82. // silence (& not even comfort noise).
  83. // 2. The audio is local. If we were to render local audio, the local
  84. // participants would be hearing themselves.
  85. const audioMuted = !audioTrack || audioTrack.muted;
  86. const renderAudio = !audioMuted && !audioTrack.local;
  87. const participantId = participant.id;
  88. const participantNotInLargeVideo
  89. = participantId !== largeVideo.participantId;
  90. const videoMuted = !videoTrack || videoTrack.muted;
  91. return (
  92. <Container
  93. onClick = { this._onClick }
  94. style = { style }>
  95. { renderAudio
  96. && <Audio
  97. stream
  98. = { audioTrack.jitsiTrack.getOriginalStream() } /> }
  99. <ParticipantView
  100. participantId = { participantId }
  101. showAvatar = { participantNotInLargeVideo }
  102. showVideo = { participantNotInLargeVideo }
  103. zOrder = { 1 } />
  104. { participant.role === PARTICIPANT_ROLE.MODERATOR
  105. && <ModeratorIndicator /> }
  106. { participant.dominantSpeaker
  107. && <DominantSpeakerIndicator /> }
  108. <Container style = { thumbToolbarStyle }>
  109. { audioMuted
  110. && <AudioMutedIndicator /> }
  111. { videoMuted
  112. && <VideoMutedIndicator /> }
  113. </Container>
  114. </Container>
  115. );
  116. }
  117. }
  118. /**
  119. * Function that maps parts of Redux state tree into component props.
  120. *
  121. * @param {Object} state - Redux state.
  122. * @param {Object} ownProps - Properties of component.
  123. * @returns {{
  124. * audioTrack: Track,
  125. * largeVideo: Object,
  126. * videoTrack: Track
  127. * }}
  128. */
  129. function mapStateToProps(state, ownProps) {
  130. // We need read-only access to the state of features/largeVideo so that the
  131. // film strip doesn't render the video of the participant who is rendered on
  132. // the stage i.e. as a large video.
  133. const largeVideo = state['features/largeVideo'];
  134. const tracks = state['features/base/tracks'];
  135. const id = ownProps.participant.id;
  136. const audioTrack
  137. = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, id);
  138. const videoTrack
  139. = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, id);
  140. return {
  141. audioTrack,
  142. largeVideo,
  143. videoTrack
  144. };
  145. }
  146. export default connect(mapStateToProps)(Thumbnail);