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.5KB

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