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.

VideoMuteButton.js 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // @flow
  2. import { connect } from 'react-redux';
  3. import {
  4. ACTION_SHORTCUT_TRIGGERED,
  5. VIDEO_MUTE,
  6. createShortcutEvent,
  7. createToolbarEvent,
  8. sendAnalytics
  9. } from '../../analytics';
  10. import { translate } from '../../base/i18n';
  11. import {
  12. MEDIA_TYPE,
  13. VIDEO_MUTISM_AUTHORITY,
  14. setVideoMuted
  15. } from '../../base/media';
  16. import { AbstractVideoMuteButton } from '../../base/toolbox';
  17. import type { AbstractButtonProps } from '../../base/toolbox';
  18. import { isLocalTrackMuted } from '../../base/tracks';
  19. declare var APP: Object;
  20. /**
  21. * The type of the React {@code Component} props of {@link VideoMuteButton}.
  22. */
  23. type Props = AbstractButtonProps & {
  24. /**
  25. * Whether the current conference is in audio only mode or not.
  26. */
  27. _audioOnly: boolean,
  28. /**
  29. * Whether video is currently muted or not.
  30. */
  31. _videoMuted: boolean,
  32. /**
  33. * The redux {@code dispatch} function.
  34. */
  35. dispatch: Function
  36. }
  37. /**
  38. * Component that renders a toolbar button for toggling video mute.
  39. *
  40. * @extends AbstractVideoMuteButton
  41. */
  42. class VideoMuteButton extends AbstractVideoMuteButton<Props, *> {
  43. label = 'toolbar.videomute';
  44. tooltip = 'toolbar.videomute';
  45. /**
  46. * Initializes a new {@code VideoMuteButton} instance.
  47. *
  48. * @param {Props} props - The read-only React {@code Component} props with
  49. * which the new instance is to be initialized.
  50. */
  51. constructor(props: Props) {
  52. super(props);
  53. // Bind event handlers so they are only bound once per instance.
  54. this._onKeyboardShortcut = this._onKeyboardShortcut.bind(this);
  55. }
  56. /**
  57. * Registers the keyboard shortcut that toggles the video muting.
  58. *
  59. * @inheritdoc
  60. * @returns {void}
  61. */
  62. componentDidMount() {
  63. typeof APP === 'undefined'
  64. || APP.keyboardshortcut.registerShortcut(
  65. 'V',
  66. null,
  67. this._onKeyboardShortcut,
  68. 'keyboardShortcuts.videoMute');
  69. }
  70. /**
  71. * Unregisters the keyboard shortcut that toggles the video muting.
  72. *
  73. * @inheritdoc
  74. * @returns {void}
  75. */
  76. componentWillUnmount() {
  77. typeof APP === 'undefined'
  78. || APP.keyboardshortcut.unregisterShortcut('V');
  79. }
  80. /**
  81. * Indicates if this button should be disabled or not.
  82. *
  83. * @override
  84. * @protected
  85. * @returns {boolean}
  86. */
  87. _isDisabled() {
  88. return this.props._audioOnly;
  89. }
  90. /**
  91. * Indicates if video is currently muted ot nor.
  92. *
  93. * @override
  94. * @protected
  95. * @returns {boolean}
  96. */
  97. _isVideoMuted() {
  98. return this.props._videoMuted;
  99. }
  100. _onKeyboardShortcut: () => void;
  101. /**
  102. * Creates an analytics keyboard shortcut event and dispatches an action to
  103. * toggle the video muting.
  104. *
  105. * @private
  106. * @returns {void}
  107. */
  108. _onKeyboardShortcut() {
  109. sendAnalytics(
  110. createShortcutEvent(
  111. VIDEO_MUTE,
  112. ACTION_SHORTCUT_TRIGGERED,
  113. { enable: !this._isVideoMuted() }));
  114. super._handleClick();
  115. }
  116. /**
  117. * Changes the muted state.
  118. *
  119. * @override
  120. * @param {boolean} videoMuted - Whether video should be muted or not.
  121. * @protected
  122. * @returns {void}
  123. */
  124. _setVideoMuted(videoMuted: boolean) {
  125. sendAnalytics(createToolbarEvent(VIDEO_MUTE, { enable: videoMuted }));
  126. this.props.dispatch(
  127. setVideoMuted(
  128. videoMuted,
  129. VIDEO_MUTISM_AUTHORITY.USER,
  130. /* ensureTrack */ true));
  131. }
  132. }
  133. /**
  134. * Maps (parts of) the redux state to the associated props for the
  135. * {@code VideoMuteButton} component.
  136. *
  137. * @param {Object} state - The Redux state.
  138. * @private
  139. * @returns {{
  140. * _audioOnly: boolean,
  141. * _videoMuted: boolean
  142. * }}
  143. */
  144. function _mapStateToProps(state): Object {
  145. const { audioOnly } = state['features/base/conference'];
  146. const tracks = state['features/base/tracks'];
  147. return {
  148. _audioOnly: Boolean(audioOnly),
  149. _videoMuted: isLocalTrackMuted(tracks, MEDIA_TYPE.VIDEO)
  150. };
  151. }
  152. export default translate(connect(_mapStateToProps)(VideoMuteButton));