Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

Thumbnail.js 4.9KB

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