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.

middleware.any.js 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // @flow
  2. import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
  3. import {
  4. CONFERENCE_JOINED
  5. } from '../base/conference';
  6. import {
  7. getLocalParticipant,
  8. getParticipantPresenceStatus,
  9. getParticipants,
  10. PARTICIPANT_JOINED,
  11. PARTICIPANT_JOINED_SOUND_ID,
  12. PARTICIPANT_LEFT,
  13. PARTICIPANT_UPDATED,
  14. pinParticipant
  15. } from '../base/participants';
  16. import { MiddlewareRegistry } from '../base/redux';
  17. import {
  18. playSound,
  19. registerSound,
  20. stopSound,
  21. unregisterSound
  22. } from '../base/sounds';
  23. import {
  24. CALLING,
  25. CONNECTED_USER,
  26. EXPIRED,
  27. INVITED,
  28. REJECTED,
  29. RINGING
  30. } from '../presence-status';
  31. import {
  32. SET_CALLEE_INFO_VISIBLE,
  33. UPDATE_DIAL_IN_NUMBERS_FAILED
  34. } from './actionTypes';
  35. import {
  36. invite,
  37. removePendingInviteRequests,
  38. setCalleeInfoVisible
  39. } from './actions';
  40. import {
  41. OUTGOING_CALL_EXPIRED_SOUND_ID,
  42. OUTGOING_CALL_REJECTED_SOUND_ID,
  43. OUTGOING_CALL_RINGING_SOUND_ID,
  44. OUTGOING_CALL_START_SOUND_ID
  45. } from './constants';
  46. import { sounds } from './sounds';
  47. const logger = require('jitsi-meet-logger').getLogger(__filename);
  48. declare var interfaceConfig: Object;
  49. /**
  50. * Maps the presence status with the ID of the sound that will be played when
  51. * the status is received.
  52. */
  53. const statusToRingtone = {
  54. [CALLING]: OUTGOING_CALL_START_SOUND_ID,
  55. [CONNECTED_USER]: PARTICIPANT_JOINED_SOUND_ID,
  56. [EXPIRED]: OUTGOING_CALL_EXPIRED_SOUND_ID,
  57. [INVITED]: OUTGOING_CALL_START_SOUND_ID,
  58. [REJECTED]: OUTGOING_CALL_REJECTED_SOUND_ID,
  59. [RINGING]: OUTGOING_CALL_RINGING_SOUND_ID
  60. };
  61. /**
  62. * The middleware of the feature invite common to mobile/react-native and
  63. * Web/React.
  64. *
  65. * @param {Store} store - The redux store.
  66. * @returns {Function}
  67. */
  68. MiddlewareRegistry.register(store => next => action => {
  69. let oldParticipantPresence;
  70. const { dispatch, getState } = store;
  71. const state = getState();
  72. if (action.type === PARTICIPANT_UPDATED
  73. || action.type === PARTICIPANT_LEFT) {
  74. oldParticipantPresence
  75. = getParticipantPresenceStatus(state, action.participant.id);
  76. }
  77. if (action.type === SET_CALLEE_INFO_VISIBLE) {
  78. if (action.calleeInfoVisible) {
  79. dispatch(pinParticipant(getLocalParticipant(state).id));
  80. } else {
  81. // unpin participant
  82. dispatch(pinParticipant());
  83. }
  84. }
  85. const result = next(action);
  86. switch (action.type) {
  87. case APP_WILL_MOUNT:
  88. for (const [ soundId, sound ] of sounds.entries()) {
  89. dispatch(registerSound(soundId, sound.file, sound.options));
  90. }
  91. break;
  92. case APP_WILL_UNMOUNT:
  93. for (const soundId of sounds.keys()) {
  94. dispatch(unregisterSound(soundId));
  95. }
  96. break;
  97. case CONFERENCE_JOINED:
  98. _onConferenceJoined(store);
  99. break;
  100. case PARTICIPANT_JOINED:
  101. case PARTICIPANT_LEFT:
  102. case PARTICIPANT_UPDATED: {
  103. _maybeHideCalleeInfo(action, store);
  104. const newParticipantPresence
  105. = getParticipantPresenceStatus(state, action.participant.id);
  106. if (oldParticipantPresence === newParticipantPresence) {
  107. break;
  108. }
  109. const oldSoundId
  110. = oldParticipantPresence
  111. && statusToRingtone[oldParticipantPresence];
  112. const newSoundId
  113. = newParticipantPresence
  114. && statusToRingtone[newParticipantPresence];
  115. if (oldSoundId === newSoundId) {
  116. break;
  117. }
  118. if (oldSoundId) {
  119. dispatch(stopSound(oldSoundId));
  120. }
  121. if (newSoundId) {
  122. dispatch(playSound(newSoundId));
  123. }
  124. break;
  125. }
  126. case UPDATE_DIAL_IN_NUMBERS_FAILED:
  127. logger.error(
  128. 'Error encountered while fetching dial-in numbers:',
  129. action.error);
  130. break;
  131. }
  132. return result;
  133. });
  134. /**
  135. * Hides the callee info layot if there are more than 1 real
  136. * (not poltergeist, shared video, etc.) participants in the call.
  137. *
  138. * @param {Object} action - The redux action.
  139. * @param {ReduxStore} store - The redux store.
  140. * @returns {void}
  141. */
  142. function _maybeHideCalleeInfo(action, store) {
  143. const state = store.getState();
  144. if (!state['features/invite'].calleeInfoVisible) {
  145. return;
  146. }
  147. const participants = getParticipants(state);
  148. const numberOfPoltergeists
  149. = participants.filter(p => p.botType === 'poltergeist').length;
  150. const numberOfRealParticipants = participants.length - numberOfPoltergeists;
  151. if ((numberOfPoltergeists > 1 || numberOfRealParticipants > 1)
  152. || (action.type === PARTICIPANT_LEFT && participants.length === 1)) {
  153. store.dispatch(setCalleeInfoVisible(false));
  154. }
  155. }
  156. /**
  157. * Executes the pending invitation requests if any.
  158. *
  159. * @param {ReduxStore} store - The redux store.
  160. * @returns {void}
  161. */
  162. function _onConferenceJoined(store) {
  163. const { dispatch, getState } = store;
  164. const pendingInviteRequests
  165. = getState()['features/invite'].pendingInviteRequests || [];
  166. pendingInviteRequests.forEach(({ invitees, callback }) => {
  167. dispatch(invite(invitees))
  168. .then(failedInvitees => {
  169. callback(failedInvitees);
  170. });
  171. });
  172. dispatch(removePendingInviteRequests());
  173. }