選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

VideoQualityLabel.web.js 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import Tooltip from '@atlaskit/tooltip';
  2. import PropTypes from 'prop-types';
  3. import React, { Component } from 'react';
  4. import { connect } from 'react-redux';
  5. import { translate } from '../../base/i18n';
  6. import { CircularLabel } from '../../base/label';
  7. import { MEDIA_TYPE } from '../../base/media';
  8. import { getTrackByMediaTypeAndParticipant } from '../../base/tracks';
  9. /**
  10. * A map of video resolution (number) to translation key.
  11. *
  12. * @type {Object}
  13. */
  14. const RESOLUTION_TO_TRANSLATION_KEY = {
  15. 720: 'videoStatus.hd',
  16. 360: 'videoStatus.sd',
  17. 180: 'videoStatus.ld'
  18. };
  19. /**
  20. * Expected video resolutions placed into an array, sorted from lowest to
  21. * highest resolution.
  22. *
  23. * @type {number[]}
  24. */
  25. const RESOLUTIONS
  26. = Object.keys(RESOLUTION_TO_TRANSLATION_KEY)
  27. .map(resolution => parseInt(resolution, 10))
  28. .sort((a, b) => a - b);
  29. /**
  30. * React {@code Component} responsible for displaying a label that indicates
  31. * the displayed video state of the current conference. {@code AudioOnlyLabel}
  32. * will display when the conference is in audio only mode. {@code HDVideoLabel}
  33. * will display if not in audio only mode and a high-definition large video is
  34. * being displayed.
  35. */
  36. export class VideoQualityLabel extends Component {
  37. /**
  38. * {@code VideoQualityLabel}'s property types.
  39. *
  40. * @static
  41. */
  42. static propTypes = {
  43. /**
  44. * Whether or not the conference is in audio only mode.
  45. */
  46. _audioOnly: PropTypes.bool,
  47. /**
  48. * The message to show within the label.
  49. */
  50. _labelKey: PropTypes.string,
  51. /**
  52. * The message to show within the label's tooltip.
  53. */
  54. _tooltipKey: PropTypes.string,
  55. /**
  56. * The redux representation of the JitsiTrack displayed on large video.
  57. */
  58. _videoTrack: PropTypes.object,
  59. /**
  60. * Invoked to obtain translated strings.
  61. */
  62. t: PropTypes.func
  63. };
  64. /**
  65. * Implements React's {@link Component#render()}.
  66. *
  67. * @inheritdoc
  68. * @returns {ReactElement}
  69. */
  70. render() {
  71. const {
  72. _audioOnly,
  73. _labelKey,
  74. _tooltipKey,
  75. _videoTrack,
  76. t
  77. } = this.props;
  78. let className, labelContent, tooltipKey;
  79. if (_audioOnly) {
  80. className = 'audio-only';
  81. labelContent = t('videoStatus.audioOnly');
  82. tooltipKey = 'videoStatus.labelTooltipAudioOnly';
  83. } else if (!_videoTrack || _videoTrack.muted) {
  84. className = 'no-video';
  85. labelContent = t('videoStatus.audioOnly');
  86. tooltipKey = 'videoStatus.labelTooiltipNoVideo';
  87. } else {
  88. className = 'current-video-quality';
  89. labelContent = t(_labelKey);
  90. tooltipKey = _tooltipKey;
  91. }
  92. return (
  93. <Tooltip
  94. content = { t(tooltipKey) }
  95. position = { 'left' }>
  96. <CircularLabel
  97. className = { className }
  98. id = 'videoResolutionLabel'>
  99. { labelContent }
  100. </CircularLabel>
  101. </Tooltip>
  102. );
  103. }
  104. }
  105. /**
  106. * Matches the passed in resolution with a translation keys for describing
  107. * the resolution. The passed in resolution will be matched with a known
  108. * resolution that it is at least greater than or equal to.
  109. *
  110. * @param {number} resolution - The video height to match with a
  111. * translation.
  112. * @private
  113. * @returns {Object}
  114. */
  115. function _mapResolutionToTranslationsKeys(resolution) {
  116. // Set the default matching resolution of the lowest just in case a match is
  117. // not found.
  118. let highestMatchingResolution = RESOLUTIONS[0];
  119. for (let i = 0; i < RESOLUTIONS.length; i++) {
  120. const knownResolution = RESOLUTIONS[i];
  121. if (resolution >= knownResolution) {
  122. highestMatchingResolution = knownResolution;
  123. } else {
  124. break;
  125. }
  126. }
  127. const labelKey
  128. = RESOLUTION_TO_TRANSLATION_KEY[highestMatchingResolution];
  129. return {
  130. labelKey,
  131. tooltipKey: `${labelKey}Tooltip`
  132. };
  133. }
  134. /**
  135. * Maps (parts of) the Redux state to the associated {@code VideoQualityLabel}'s
  136. * props.
  137. *
  138. * @param {Object} state - The Redux state.
  139. * @private
  140. * @returns {{
  141. * _audioOnly: boolean,
  142. * _labelKey: string,
  143. * _tooltipKey: string,
  144. * _videoTrack: Object
  145. * }}
  146. */
  147. function _mapStateToProps(state) {
  148. const { audioOnly } = state['features/base/conference'];
  149. const { resolution, participantId } = state['features/large-video'];
  150. const videoTrackOnLargeVideo = getTrackByMediaTypeAndParticipant(
  151. state['features/base/tracks'],
  152. MEDIA_TYPE.VIDEO,
  153. participantId
  154. );
  155. const translationKeys
  156. = audioOnly ? {} : _mapResolutionToTranslationsKeys(resolution);
  157. return {
  158. _audioOnly: audioOnly,
  159. _labelKey: translationKeys.labelKey,
  160. _tooltipKey: translationKeys.tooltipKey,
  161. _videoTrack: videoTrackOnLargeVideo
  162. };
  163. }
  164. export default translate(connect(_mapStateToProps)(VideoQualityLabel));