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

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