您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

middleware.js 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // @flow
  2. import { NativeEventEmitter, NativeModules } from 'react-native';
  3. import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../../base/app';
  4. import { SET_AUDIO_ONLY } from '../../base/audio-only';
  5. import {
  6. CONFERENCE_FAILED,
  7. CONFERENCE_LEFT,
  8. CONFERENCE_JOINED,
  9. getCurrentConference
  10. } from '../../base/conference';
  11. import { getFeatureFlag, AUDIO_FOCUS_DISABLED } from '../../base/flags';
  12. import { MiddlewareRegistry } from '../../base/redux';
  13. import { _SET_AUDIOMODE_DEVICES, _SET_AUDIOMODE_SUBSCRIPTIONS } from './actionTypes';
  14. import logger from './logger';
  15. const { AudioMode } = NativeModules;
  16. const AudioModeEmitter = new NativeEventEmitter(AudioMode);
  17. /**
  18. * Middleware that captures conference actions and sets the correct audio mode
  19. * based on the type of conference. Audio-only conferences don't use the speaker
  20. * by default, and video conferences do.
  21. *
  22. * @param {Store} store - The redux store.
  23. * @returns {Function}
  24. */
  25. MiddlewareRegistry.register(store => next => action => {
  26. /* eslint-disable no-fallthrough */
  27. switch (action.type) {
  28. case _SET_AUDIOMODE_SUBSCRIPTIONS:
  29. _setSubscriptions(store);
  30. break;
  31. case APP_WILL_UNMOUNT: {
  32. store.dispatch({
  33. type: _SET_AUDIOMODE_SUBSCRIPTIONS,
  34. subscriptions: undefined
  35. });
  36. break;
  37. }
  38. case APP_WILL_MOUNT:
  39. _appWillMount(store);
  40. case CONFERENCE_FAILED: // eslint-disable-line no-fallthrough
  41. case CONFERENCE_LEFT:
  42. /*
  43. * NOTE: We moved the audio mode setting from CONFERENCE_WILL_JOIN to
  44. * CONFERENCE_JOINED because in case of a locked room, the app goes
  45. * through CONFERENCE_FAILED state and gets to CONFERENCE_JOINED only
  46. * after a correct password, so we want to make sure we have the correct
  47. * audio mode set up when we finally get to the conf, but also make sure
  48. * that the app is in the right audio mode if the user leaves the
  49. * conference after the password prompt appears.
  50. */
  51. case CONFERENCE_JOINED:
  52. case SET_AUDIO_ONLY:
  53. return _updateAudioMode(store, next, action);
  54. }
  55. /* eslint-enable no-fallthrough */
  56. return next(action);
  57. });
  58. /**
  59. * Notifies this feature that the action {@link APP_WILL_MOUNT} is being
  60. * dispatched within a specific redux {@code store}.
  61. *
  62. * @param {Store} store - The redux store in which the specified {@code action}
  63. * is being dispatched.
  64. * @private
  65. * @returns {void}
  66. */
  67. function _appWillMount(store) {
  68. const subscriptions = [
  69. AudioModeEmitter.addListener(AudioMode.DEVICE_CHANGE_EVENT, _onDevicesUpdate, store)
  70. ];
  71. store.dispatch({
  72. type: _SET_AUDIOMODE_SUBSCRIPTIONS,
  73. subscriptions
  74. });
  75. }
  76. /**
  77. * Handles audio device changes. The list will be stored on the redux store.
  78. *
  79. * @param {Object} devices - The current list of devices.
  80. * @private
  81. * @returns {void}
  82. */
  83. function _onDevicesUpdate(devices) {
  84. const { dispatch } = this; // eslint-disable-line no-invalid-this
  85. dispatch({
  86. type: _SET_AUDIOMODE_DEVICES,
  87. devices
  88. });
  89. }
  90. /**
  91. * Notifies this feature that the action
  92. * {@link _SET_AUDIOMODE_SUBSCRIPTIONS} is being dispatched within
  93. * a specific redux {@code store}.
  94. *
  95. * @param {Store} store - The redux store in which the specified {@code action}
  96. * is being dispatched.
  97. * @private
  98. * @returns {void}
  99. */
  100. function _setSubscriptions({ getState }) {
  101. const { subscriptions } = getState()['features/mobile/audio-mode'];
  102. if (subscriptions) {
  103. for (const subscription of subscriptions) {
  104. subscription.remove();
  105. }
  106. }
  107. }
  108. /**
  109. * Updates the audio mode based on the current (redux) state.
  110. *
  111. * @param {Store} store - The redux store in which the specified {@code action}
  112. * is being dispatched.
  113. * @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
  114. * specified {@code action} in the specified {@code store}.
  115. * @param {Action} action - The redux action which is
  116. * being dispatched in the specified {@code store}.
  117. * @private
  118. * @returns {*} The value returned by {@code next(action)}.
  119. */
  120. function _updateAudioMode({ getState }, next, action) {
  121. const result = next(action);
  122. const state = getState();
  123. const conference = getCurrentConference(state);
  124. const { enabled: audioOnly } = state['features/base/audio-only'];
  125. let mode;
  126. if (getFeatureFlag(state, AUDIO_FOCUS_DISABLED, false)) {
  127. return result;
  128. } else if (conference) {
  129. mode = audioOnly ? AudioMode.AUDIO_CALL : AudioMode.VIDEO_CALL;
  130. } else {
  131. mode = AudioMode.DEFAULT;
  132. }
  133. AudioMode.setMode(mode).catch(err => logger.error(`Failed to set audio mode ${String(mode)}: ${err}`));
  134. return result;
  135. }