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 5.3KB

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