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.js 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /* @flow */
  2. import UIEvents from '../../../../service/UI/UIEvents';
  3. import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../../app';
  4. import {
  5. CONFERENCE_JOINED,
  6. CONFERENCE_LEFT
  7. } from '../conference';
  8. import { MiddlewareRegistry } from '../redux';
  9. import { playSound, registerSound, unregisterSound } from '../sounds';
  10. import { localParticipantIdChanged } from './actions';
  11. import {
  12. KICK_PARTICIPANT,
  13. MUTE_REMOTE_PARTICIPANT,
  14. PARTICIPANT_DISPLAY_NAME_CHANGED,
  15. PARTICIPANT_JOINED,
  16. PARTICIPANT_LEFT,
  17. PARTICIPANT_UPDATED
  18. } from './actionTypes';
  19. import {
  20. LOCAL_PARTICIPANT_DEFAULT_ID,
  21. PARTICIPANT_JOINED_SOUND_ID,
  22. PARTICIPANT_LEFT_SOUND_ID
  23. } from './constants';
  24. import {
  25. getAvatarURLByParticipantId,
  26. getLocalParticipant,
  27. getParticipantCount
  28. } from './functions';
  29. import {
  30. PARTICIPANT_JOINED_SRC,
  31. PARTICIPANT_LEFT_SRC
  32. } from './sounds';
  33. declare var APP: Object;
  34. /**
  35. * Middleware that captures CONFERENCE_JOINED and CONFERENCE_LEFT actions and
  36. * updates respectively ID of local participant.
  37. *
  38. * @param {Store} store - Redux store.
  39. * @returns {Function}
  40. */
  41. MiddlewareRegistry.register(store => next => action => {
  42. const { conference } = store.getState()['features/base/conference'];
  43. if (action.type === PARTICIPANT_JOINED
  44. || action.type === PARTICIPANT_LEFT) {
  45. _maybePlaySounds(store, action);
  46. }
  47. switch (action.type) {
  48. case APP_WILL_MOUNT:
  49. _registerSounds(store);
  50. break;
  51. case APP_WILL_UNMOUNT:
  52. _unregisterSounds(store);
  53. break;
  54. case CONFERENCE_JOINED:
  55. store.dispatch(localParticipantIdChanged(action.conference.myUserId()));
  56. break;
  57. case CONFERENCE_LEFT:
  58. store.dispatch(localParticipantIdChanged(LOCAL_PARTICIPANT_DEFAULT_ID));
  59. break;
  60. case KICK_PARTICIPANT:
  61. conference.kickParticipant(action.id);
  62. break;
  63. case MUTE_REMOTE_PARTICIPANT:
  64. conference.muteParticipant(action.id);
  65. break;
  66. // TODO Remove this middleware when the local display name update flow is
  67. // fully brought into redux.
  68. case PARTICIPANT_DISPLAY_NAME_CHANGED: {
  69. if (typeof APP !== 'undefined') {
  70. const participant = getLocalParticipant(store.getState());
  71. if (participant && participant.id === action.id) {
  72. APP.UI.emitEvent(UIEvents.NICKNAME_CHANGED, action.name);
  73. }
  74. }
  75. break;
  76. }
  77. case PARTICIPANT_JOINED:
  78. case PARTICIPANT_UPDATED: {
  79. if (typeof APP !== 'undefined') {
  80. const participant = action.participant;
  81. const { id, local } = participant;
  82. const preUpdateAvatarURL
  83. = getAvatarURLByParticipantId(store.getState(), id);
  84. // Allow the redux update to go through and compare the old avatar
  85. // to the new avatar and emit out change events if necessary.
  86. const result = next(action);
  87. const postUpdateAvatarURL
  88. = getAvatarURLByParticipantId(store.getState(), id);
  89. if (preUpdateAvatarURL !== postUpdateAvatarURL) {
  90. const currentKnownId = local
  91. ? APP.conference.getMyUserId() : id;
  92. APP.UI.refreshAvatarDisplay(
  93. currentKnownId, postUpdateAvatarURL);
  94. APP.API.notifyAvatarChanged(
  95. currentKnownId, postUpdateAvatarURL);
  96. }
  97. return result;
  98. }
  99. break;
  100. }
  101. }
  102. return next(action);
  103. });
  104. /**
  105. * Plays sounds when participants join/leave conference.
  106. *
  107. * @param {Store} store - The Redux store.
  108. * @param {Action} action - The Redux action. Should be either
  109. * {@link PARTICIPANT_JOINED} or {@link PARTICIPANT_LEFT}.
  110. * @private
  111. * @returns {void}
  112. */
  113. function _maybePlaySounds({ getState, dispatch }, action) {
  114. const state = getState();
  115. const { startAudioMuted } = state['features/base/config'];
  116. // We're not playing sounds for local participant
  117. // nor when the user is joining past the "startAudioMuted" limit.
  118. // The intention there was to not play user joined notification in big
  119. // conferences where 100th person is joining.
  120. if (!action.participant.local
  121. && (!startAudioMuted
  122. || getParticipantCount(state) < startAudioMuted)) {
  123. if (action.type === PARTICIPANT_JOINED) {
  124. dispatch(playSound(PARTICIPANT_JOINED_SOUND_ID));
  125. } else if (action.type === PARTICIPANT_LEFT) {
  126. dispatch(playSound(PARTICIPANT_LEFT_SOUND_ID));
  127. }
  128. }
  129. }
  130. /**
  131. * Registers sounds related with the participants feature.
  132. *
  133. * @param {Store} store - The Redux store.
  134. * @private
  135. * @returns {void}
  136. */
  137. function _registerSounds({ dispatch }) {
  138. dispatch(
  139. registerSound(PARTICIPANT_JOINED_SOUND_ID, PARTICIPANT_JOINED_SRC));
  140. dispatch(
  141. registerSound(PARTICIPANT_LEFT_SOUND_ID, PARTICIPANT_LEFT_SRC));
  142. }
  143. /**
  144. * Unregisters sounds related with the participants feature.
  145. *
  146. * @param {Store} store - The Redux store.
  147. * @private
  148. * @returns {void}
  149. */
  150. function _unregisterSounds({ dispatch }) {
  151. dispatch(
  152. unregisterSound(PARTICIPANT_JOINED_SOUND_ID, PARTICIPANT_JOINED_SRC));
  153. dispatch(
  154. unregisterSound(PARTICIPANT_LEFT_SOUND_ID, PARTICIPANT_LEFT_SRC));
  155. }