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.

AbstractLiveStreamButton.ts 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import { IReduxState } from '../../../app/types';
  2. import { IconSites } from '../../../base/icons/svg';
  3. import { MEET_FEATURES } from '../../../base/jwt/constants';
  4. import { isJwtFeatureEnabled } from '../../../base/jwt/functions';
  5. import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
  6. import { isLocalParticipantModerator } from '../../../base/participants/functions';
  7. import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
  8. import { isInBreakoutRoom } from '../../../breakout-rooms/functions';
  9. import { maybeShowPremiumFeatureDialog } from '../../../jaas/actions';
  10. import { isRecorderTranscriptionsRunning } from '../../../transcribing/functions';
  11. import { getActiveSession, isCloudRecordingRunning, isLiveStreamingButtonVisible } from '../../functions';
  12. import { getLiveStreaming } from './functions';
  13. /**
  14. * The type of the React {@code Component} props of
  15. * {@link AbstractLiveStreamButton}.
  16. */
  17. export interface IProps extends AbstractButtonProps {
  18. /**
  19. * True if the button needs to be disabled.
  20. */
  21. _disabled: boolean;
  22. /**
  23. * True if there is a running active live stream, false otherwise.
  24. */
  25. _isLiveStreamRunning: boolean;
  26. /**
  27. * The tooltip to display when hovering over the button.
  28. */
  29. _tooltip?: string;
  30. }
  31. /**
  32. * An abstract class of a button for starting and stopping live streaming.
  33. */
  34. export default class AbstractLiveStreamButton<P extends IProps> extends AbstractButton<P> {
  35. accessibilityLabel = 'dialog.startLiveStreaming';
  36. toggledAccessibilityLabel = 'dialog.stopLiveStreaming';
  37. icon = IconSites;
  38. label = 'dialog.startLiveStreaming';
  39. toggledLabel = 'dialog.stopLiveStreaming';
  40. /**
  41. * Returns the tooltip that should be displayed when the button is disabled.
  42. *
  43. * @private
  44. * @returns {string}
  45. */
  46. _getTooltip() {
  47. return this.props._tooltip ?? '';
  48. }
  49. /**
  50. * Helper function to be implemented by subclasses, which should be used
  51. * to handle the live stream button being clicked / pressed.
  52. *
  53. * @protected
  54. * @returns {void}
  55. */
  56. _onHandleClick() {
  57. // To be implemented by subclass.
  58. }
  59. /**
  60. * Handles clicking / pressing the button.
  61. *
  62. * @override
  63. * @protected
  64. * @returns {void}
  65. */
  66. async _handleClick() {
  67. const { dispatch } = this.props;
  68. const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(MEET_FEATURES.RECORDING));
  69. if (!dialogShown) {
  70. this._onHandleClick();
  71. }
  72. }
  73. /**
  74. * Returns a boolean value indicating if this button is disabled or not.
  75. *
  76. * @protected
  77. * @returns {boolean}
  78. */
  79. _isDisabled() {
  80. return this.props._disabled;
  81. }
  82. /**
  83. * Indicates whether this button is in toggled state or not.
  84. *
  85. * @override
  86. * @protected
  87. * @returns {boolean}
  88. */
  89. _isToggled() {
  90. return this.props._isLiveStreamRunning;
  91. }
  92. }
  93. /**
  94. * Maps (parts of) the redux state to the associated props for the
  95. * {@code AbstractLiveStreamButton} component.
  96. *
  97. * @param {Object} state - The Redux state.
  98. * @param {IProps} ownProps - The own props of the Component.
  99. * @private
  100. * @returns {{
  101. * _disabled: boolean,
  102. * _isLiveStreamRunning: boolean,
  103. * visible: boolean
  104. * }}
  105. */
  106. export function _mapStateToProps(state: IReduxState, ownProps: IProps) {
  107. let { visible } = ownProps;
  108. // A button can be disabled/enabled only if enableFeaturesBasedOnToken
  109. // is on or if the recording is running.
  110. let _disabled = false;
  111. let _tooltip = '';
  112. if (typeof visible === 'undefined') {
  113. // If the containing component provides the visible prop, that is one
  114. // above all, but if not, the button should be autonomous and decide on
  115. // its own to be visible or not.
  116. const isModerator = isLocalParticipantModerator(state);
  117. const liveStreaming = getLiveStreaming(state);
  118. visible = isLiveStreamingButtonVisible({
  119. localParticipantIsModerator: isModerator,
  120. liveStreamingEnabled: liveStreaming?.enabled,
  121. liveStreamingEnabledInJwt: isJwtFeatureEnabled(state, 'livestreaming', true),
  122. isInBreakoutRoom: isInBreakoutRoom(state)
  123. });
  124. }
  125. // disable the button if the recording is running.
  126. if (visible && (isCloudRecordingRunning(state) || isRecorderTranscriptionsRunning(state))) {
  127. _disabled = true;
  128. _tooltip = 'dialog.liveStreamingDisabledBecauseOfActiveRecordingTooltip';
  129. }
  130. // disable the button if we are in a breakout room.
  131. if (isInBreakoutRoom(state)) {
  132. _disabled = true;
  133. }
  134. return {
  135. _disabled,
  136. _isLiveStreamRunning: Boolean(getActiveSession(state, JitsiRecordingConstants.mode.STREAM)),
  137. _tooltip,
  138. visible
  139. };
  140. }