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.

reducer.js 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /* @flow */
  2. import { MEDIA_TYPE } from '../base/media/constants';
  3. import type { MediaType } from '../base/media/constants';
  4. import {
  5. PARTICIPANT_LEFT,
  6. PARTICIPANT_UPDATED
  7. } from '../base/participants';
  8. import { ReducerRegistry } from '../base/redux';
  9. import {
  10. DISABLE_MODERATION,
  11. DISMISS_PENDING_PARTICIPANT,
  12. ENABLE_MODERATION,
  13. LOCAL_PARTICIPANT_APPROVED,
  14. LOCAL_PARTICIPANT_REJECTED,
  15. PARTICIPANT_APPROVED,
  16. PARTICIPANT_PENDING_AUDIO,
  17. PARTICIPANT_REJECTED
  18. } from './actionTypes';
  19. import { MEDIA_TYPE_TO_PENDING_STORE_KEY } from './constants';
  20. const initialState = {
  21. audioModerationEnabled: false,
  22. videoModerationEnabled: false,
  23. audioWhitelist: {},
  24. videoWhitelist: {},
  25. pendingAudio: [],
  26. pendingVideo: []
  27. };
  28. /**
  29. Updates a participant in the state for the specified media type.
  30. *
  31. * @param {MediaType} mediaType - The media type.
  32. * @param {Object} participant - Information about participant to be modified.
  33. * @param {Object} state - The current state.
  34. * @private
  35. * @returns {boolean} - Whether state instance was modified.
  36. */
  37. function _updatePendingParticipant(mediaType: MediaType, participant, state: Object = {}) {
  38. let arrayItemChanged = false;
  39. const storeKey = MEDIA_TYPE_TO_PENDING_STORE_KEY[mediaType];
  40. const arr = state[storeKey];
  41. const newArr = arr.map(pending => {
  42. if (pending.id === participant.id) {
  43. arrayItemChanged = true;
  44. return {
  45. ...pending,
  46. ...participant
  47. };
  48. }
  49. return pending;
  50. });
  51. if (arrayItemChanged) {
  52. state[storeKey] = newArr;
  53. return true;
  54. }
  55. return false;
  56. }
  57. ReducerRegistry.register('features/av-moderation', (state = initialState, action) => {
  58. switch (action.type) {
  59. case DISABLE_MODERATION: {
  60. const newState = action.mediaType === MEDIA_TYPE.AUDIO
  61. ? {
  62. audioModerationEnabled: false,
  63. audioUnmuteApproved: undefined
  64. } : {
  65. videoModerationEnabled: false,
  66. videoUnmuteApproved: undefined
  67. };
  68. return {
  69. ...state,
  70. ...newState,
  71. audioWhitelist: {},
  72. videoWhitelist: {},
  73. pendingAudio: [],
  74. pendingVideo: []
  75. };
  76. }
  77. case ENABLE_MODERATION: {
  78. const newState = action.mediaType === MEDIA_TYPE.AUDIO
  79. ? { audioModerationEnabled: true } : { videoModerationEnabled: true };
  80. return {
  81. ...state,
  82. ...newState
  83. };
  84. }
  85. case LOCAL_PARTICIPANT_APPROVED: {
  86. const newState = action.mediaType === MEDIA_TYPE.AUDIO
  87. ? { audioUnmuteApproved: true } : { videoUnmuteApproved: true };
  88. return {
  89. ...state,
  90. ...newState
  91. };
  92. }
  93. case LOCAL_PARTICIPANT_REJECTED: {
  94. const newState = action.mediaType === MEDIA_TYPE.AUDIO
  95. ? { audioUnmuteApproved: false } : { videoUnmuteApproved: false };
  96. return {
  97. ...state,
  98. ...newState
  99. };
  100. }
  101. case PARTICIPANT_PENDING_AUDIO: {
  102. const { participant } = action;
  103. // Add participant to pendingAudio array only if it's not already added
  104. if (!state.pendingAudio.find(pending => pending.id === participant.id)) {
  105. const updated = [ ...state.pendingAudio ];
  106. updated.push(participant);
  107. return {
  108. ...state,
  109. pendingAudio: updated
  110. };
  111. }
  112. return state;
  113. }
  114. case PARTICIPANT_UPDATED: {
  115. const participant = action.participant;
  116. const { audioModerationEnabled, videoModerationEnabled } = state;
  117. let hasStateChanged = false;
  118. // skips changing the reference of pendingAudio or pendingVideo,
  119. // if there is no change in the elements
  120. if (audioModerationEnabled) {
  121. hasStateChanged = _updatePendingParticipant(MEDIA_TYPE.AUDIO, participant, state);
  122. }
  123. if (videoModerationEnabled) {
  124. hasStateChanged = hasStateChanged || _updatePendingParticipant(MEDIA_TYPE.VIDEO, participant, state);
  125. }
  126. // If the state has changed we need to return a new object reference in order to trigger subscriber updates.
  127. if (hasStateChanged) {
  128. return {
  129. ...state
  130. };
  131. }
  132. return state;
  133. }
  134. case PARTICIPANT_LEFT: {
  135. const participant = action.participant;
  136. const { audioModerationEnabled, videoModerationEnabled } = state;
  137. let hasStateChanged = false;
  138. // skips changing the reference of pendingAudio or pendingVideo,
  139. // if there is no change in the elements
  140. if (audioModerationEnabled) {
  141. const newPendingAudio = state.pendingAudio.filter(pending => pending.id !== participant.id);
  142. if (state.pendingAudio.length !== newPendingAudio.length) {
  143. state.pendingAudio = newPendingAudio;
  144. hasStateChanged = true;
  145. }
  146. }
  147. if (videoModerationEnabled) {
  148. const newPendingVideo = state.pendingVideo.filter(pending => pending.id !== participant.id);
  149. if (state.pendingVideo.length !== newPendingVideo.length) {
  150. state.pendingVideo = newPendingVideo;
  151. hasStateChanged = true;
  152. }
  153. }
  154. // If the state has changed we need to return a new object reference in order to trigger subscriber updates.
  155. if (hasStateChanged) {
  156. return {
  157. ...state
  158. };
  159. }
  160. return state;
  161. }
  162. case DISMISS_PENDING_PARTICIPANT: {
  163. const { id, mediaType } = action;
  164. if (mediaType === MEDIA_TYPE.AUDIO) {
  165. return {
  166. ...state,
  167. pendingAudio: state.pendingAudio.filter(pending => pending.id !== id)
  168. };
  169. }
  170. if (mediaType === MEDIA_TYPE.VIDEO) {
  171. return {
  172. ...state,
  173. pendingVideo: state.pendingVideo.filter(pending => pending.id !== id)
  174. };
  175. }
  176. return state;
  177. }
  178. case PARTICIPANT_APPROVED: {
  179. const { mediaType, id } = action;
  180. if (mediaType === MEDIA_TYPE.AUDIO) {
  181. return {
  182. ...state,
  183. audioWhitelist: {
  184. ...state.audioWhitelist,
  185. [id]: true
  186. }
  187. };
  188. }
  189. if (mediaType === MEDIA_TYPE.VIDEO) {
  190. return {
  191. ...state,
  192. videoWhitelist: {
  193. ...state.videoWhitelist,
  194. [id]: true
  195. }
  196. };
  197. }
  198. return state;
  199. }
  200. case PARTICIPANT_REJECTED: {
  201. const { mediaType, id } = action;
  202. if (mediaType === MEDIA_TYPE.AUDIO) {
  203. return {
  204. ...state,
  205. audioWhitelist: {
  206. ...state.audioWhitelist,
  207. [id]: false
  208. }
  209. };
  210. }
  211. if (mediaType === MEDIA_TYPE.VIDEO) {
  212. return {
  213. ...state,
  214. videoWhitelist: {
  215. ...state.videoWhitelist,
  216. [id]: false
  217. }
  218. };
  219. }
  220. return state;
  221. }
  222. }
  223. return state;
  224. });