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.

AudioSettingsButton.js 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // @flow
  2. import React, { Component } from 'react';
  3. import { isMobileBrowser } from '../../../base/environment/utils';
  4. import { IconArrowDown } from '../../../base/icons';
  5. import JitsiMeetJS from '../../../base/lib-jitsi-meet/_';
  6. import { connect } from '../../../base/redux';
  7. import { ToolboxButtonWithIcon } from '../../../base/toolbox/components';
  8. import { getMediaPermissionPromptVisibility } from '../../../overlay';
  9. import { AudioSettingsPopup, toggleAudioSettings } from '../../../settings';
  10. import { isAudioSettingsButtonDisabled } from '../../functions';
  11. import AudioMuteButton from '../AudioMuteButton';
  12. type Props = {
  13. /**
  14. * Click handler for the small icon. Opens audio options.
  15. */
  16. onAudioOptionsClick: Function,
  17. /**
  18. * Whether the permission prompt is visible or not.
  19. * Useful for enabling the button on permission grant.
  20. */
  21. permissionPromptVisibility: boolean,
  22. /**
  23. * If the button should be disabled.
  24. */
  25. isDisabled: boolean,
  26. /**
  27. * Flag controlling the visibility of the button.
  28. * AudioSettings popup is disabled on mobile browsers.
  29. */
  30. visible: boolean,
  31. };
  32. type State = {
  33. /**
  34. * If there are permissions for audio devices.
  35. */
  36. hasPermissions: boolean,
  37. }
  38. /**
  39. * Button used for audio & audio settings.
  40. *
  41. * @returns {ReactElement}
  42. */
  43. class AudioSettingsButton extends Component<Props, State> {
  44. _isMounted: boolean;
  45. /**
  46. * Initializes a new {@code AudioSettingsButton} instance.
  47. *
  48. * @param {Object} props - The read-only properties with which the new
  49. * instance is to be initialized.
  50. */
  51. constructor(props) {
  52. super(props);
  53. this._isMounted = true;
  54. this.state = {
  55. hasPermissions: false
  56. };
  57. }
  58. /**
  59. * Updates device permissions.
  60. *
  61. * @returns {Promise<void>}
  62. */
  63. async _updatePermissions() {
  64. const hasPermissions = await JitsiMeetJS.mediaDevices.isDevicePermissionGranted(
  65. 'audio',
  66. );
  67. this._isMounted && this.setState({
  68. hasPermissions
  69. });
  70. }
  71. /**
  72. * Implements React's {@link Component#componentDidMount}.
  73. *
  74. * @inheritdoc
  75. */
  76. componentDidMount() {
  77. this._updatePermissions();
  78. }
  79. /**
  80. * Implements React's {@link Component#componentDidUpdate}.
  81. *
  82. * @inheritdoc
  83. */
  84. componentDidUpdate(prevProps) {
  85. if (this.props.permissionPromptVisibility !== prevProps.permissionPromptVisibility) {
  86. this._updatePermissions();
  87. }
  88. }
  89. /**
  90. * Implements React's {@link Component#componentWillUnmount}.
  91. *
  92. * @inheritdoc
  93. */
  94. componentWillUnmount() {
  95. this._isMounted = false;
  96. }
  97. /**
  98. * Implements React's {@link Component#render}.
  99. *
  100. * @inheritdoc
  101. */
  102. render() {
  103. const { isDisabled, onAudioOptionsClick, visible } = this.props;
  104. const settingsDisabled = !this.state.hasPermissions
  105. || isDisabled
  106. || !JitsiMeetJS.mediaDevices.isMultipleAudioInputSupported();
  107. return visible ? (
  108. <AudioSettingsPopup>
  109. <ToolboxButtonWithIcon
  110. icon = { IconArrowDown }
  111. iconDisabled = { settingsDisabled }
  112. onIconClick = { onAudioOptionsClick }>
  113. <AudioMuteButton />
  114. </ToolboxButtonWithIcon>
  115. </AudioSettingsPopup>
  116. ) : <AudioMuteButton />;
  117. }
  118. }
  119. /**
  120. * Function that maps parts of Redux state tree into component props.
  121. *
  122. * @param {Object} state - Redux state.
  123. * @returns {Object}
  124. */
  125. function mapStateToProps(state) {
  126. return {
  127. isDisabled: isAudioSettingsButtonDisabled(state),
  128. permissionPromptVisibility: getMediaPermissionPromptVisibility(state),
  129. visible: !isMobileBrowser()
  130. };
  131. }
  132. const mapDispatchToProps = {
  133. onAudioOptionsClick: toggleAudioSettings
  134. };
  135. export default connect(
  136. mapStateToProps,
  137. mapDispatchToProps,
  138. )(AudioSettingsButton);