Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

middleware.js 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /* @flow */
  2. import {
  3. createRecordingEvent,
  4. sendAnalytics
  5. } from '../analytics';
  6. import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
  7. import { CONFERENCE_WILL_JOIN, getCurrentConference } from '../base/conference';
  8. import JitsiMeetJS, {
  9. JitsiConferenceEvents,
  10. JitsiRecordingConstants
  11. } from '../base/lib-jitsi-meet';
  12. import { getParticipantDisplayName } from '../base/participants';
  13. import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
  14. import {
  15. playSound,
  16. registerSound,
  17. stopSound,
  18. unregisterSound
  19. } from '../base/sounds';
  20. import { RECORDING_SESSION_UPDATED } from './actionTypes';
  21. import {
  22. clearRecordingSessions,
  23. hidePendingRecordingNotification,
  24. showPendingRecordingNotification,
  25. showRecordingError,
  26. showRecordingLimitNotification,
  27. showStartedRecordingNotification,
  28. showStoppedRecordingNotification,
  29. updateRecordingSessionData
  30. } from './actions';
  31. import {
  32. LIVE_STREAMING_OFF_SOUND_ID,
  33. LIVE_STREAMING_ON_SOUND_ID,
  34. RECORDING_OFF_SOUND_ID,
  35. RECORDING_ON_SOUND_ID
  36. } from './constants';
  37. import { getSessionById, getResourceId } from './functions';
  38. import {
  39. LIVE_STREAMING_OFF_SOUND_FILE,
  40. LIVE_STREAMING_ON_SOUND_FILE,
  41. RECORDING_OFF_SOUND_FILE,
  42. RECORDING_ON_SOUND_FILE
  43. } from './sounds';
  44. declare var APP: Object;
  45. declare var interfaceConfig: Object;
  46. /**
  47. * StateListenerRegistry provides a reliable way to detect the leaving of a
  48. * conference, where we need to clean up the recording sessions.
  49. */
  50. StateListenerRegistry.register(
  51. /* selector */ state => getCurrentConference(state),
  52. /* listener */ (conference, { dispatch }) => {
  53. if (!conference) {
  54. dispatch(clearRecordingSessions());
  55. }
  56. }
  57. );
  58. /**
  59. * The redux middleware to handle the recorder updates in a React way.
  60. *
  61. * @param {Store} store - The redux store.
  62. * @returns {Function}
  63. */
  64. MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
  65. let oldSessionData;
  66. if (action.type === RECORDING_SESSION_UPDATED) {
  67. oldSessionData
  68. = getSessionById(getState(), action.sessionData.id);
  69. }
  70. const result = next(action);
  71. switch (action.type) {
  72. case APP_WILL_MOUNT:
  73. dispatch(registerSound(
  74. LIVE_STREAMING_OFF_SOUND_ID,
  75. LIVE_STREAMING_OFF_SOUND_FILE));
  76. dispatch(registerSound(
  77. LIVE_STREAMING_ON_SOUND_ID,
  78. LIVE_STREAMING_ON_SOUND_FILE));
  79. dispatch(registerSound(
  80. RECORDING_OFF_SOUND_ID,
  81. RECORDING_OFF_SOUND_FILE));
  82. dispatch(registerSound(
  83. RECORDING_ON_SOUND_ID,
  84. RECORDING_ON_SOUND_FILE));
  85. break;
  86. case APP_WILL_UNMOUNT:
  87. dispatch(unregisterSound(LIVE_STREAMING_OFF_SOUND_ID));
  88. dispatch(unregisterSound(LIVE_STREAMING_ON_SOUND_ID));
  89. dispatch(unregisterSound(RECORDING_OFF_SOUND_ID));
  90. dispatch(unregisterSound(RECORDING_ON_SOUND_ID));
  91. break;
  92. case CONFERENCE_WILL_JOIN: {
  93. const { conference } = action;
  94. conference.on(
  95. JitsiConferenceEvents.RECORDER_STATE_CHANGED,
  96. recorderSession => {
  97. if (recorderSession) {
  98. recorderSession.getID()
  99. && dispatch(
  100. updateRecordingSessionData(recorderSession));
  101. recorderSession.getError()
  102. && _showRecordingErrorNotification(
  103. recorderSession, dispatch);
  104. }
  105. return;
  106. });
  107. break;
  108. }
  109. case RECORDING_SESSION_UPDATED: {
  110. // When in recorder mode no notifications are shown
  111. // or extra sounds are also not desired
  112. // but we want to indicate those in case of sip gateway
  113. const {
  114. iAmRecorder,
  115. iAmSipGateway,
  116. recordingLimit
  117. } = getState()['features/base/config'];
  118. if (iAmRecorder && !iAmSipGateway) {
  119. break;
  120. }
  121. const updatedSessionData
  122. = getSessionById(getState(), action.sessionData.id);
  123. const { initiator, mode, terminator } = updatedSessionData;
  124. const { PENDING, OFF, ON } = JitsiRecordingConstants.status;
  125. if (updatedSessionData.status === PENDING
  126. && (!oldSessionData || oldSessionData.status !== PENDING)) {
  127. dispatch(showPendingRecordingNotification(mode));
  128. } else if (updatedSessionData.status !== PENDING) {
  129. dispatch(hidePendingRecordingNotification(mode));
  130. if (updatedSessionData.status === ON
  131. && (!oldSessionData || oldSessionData.status !== ON)) {
  132. if (typeof recordingLimit === 'object') {
  133. // Show notification with additional information to the initiator.
  134. dispatch(showRecordingLimitNotification(mode));
  135. } else {
  136. dispatch(showStartedRecordingNotification(mode, initiator, action.sessionData.id));
  137. }
  138. sendAnalytics(createRecordingEvent('start', mode));
  139. let soundID;
  140. if (mode === JitsiRecordingConstants.mode.FILE) {
  141. soundID = RECORDING_ON_SOUND_ID;
  142. } else if (mode === JitsiRecordingConstants.mode.STREAM) {
  143. soundID = LIVE_STREAMING_ON_SOUND_ID;
  144. }
  145. if (soundID) {
  146. dispatch(playSound(soundID));
  147. }
  148. if (typeof APP !== 'undefined') {
  149. APP.API.notifyRecordingStatusChanged(true, mode);
  150. }
  151. } else if (updatedSessionData.status === OFF
  152. && (!oldSessionData || oldSessionData.status !== OFF)) {
  153. if (terminator) {
  154. dispatch(
  155. showStoppedRecordingNotification(
  156. mode, getParticipantDisplayName(getState, getResourceId(terminator))));
  157. }
  158. let duration = 0, soundOff, soundOn;
  159. if (oldSessionData && oldSessionData.timestamp) {
  160. duration
  161. = (Date.now() / 1000) - oldSessionData.timestamp;
  162. }
  163. sendAnalytics(createRecordingEvent('stop', mode, duration));
  164. if (mode === JitsiRecordingConstants.mode.FILE) {
  165. soundOff = RECORDING_OFF_SOUND_ID;
  166. soundOn = RECORDING_ON_SOUND_ID;
  167. } else if (mode === JitsiRecordingConstants.mode.STREAM) {
  168. soundOff = LIVE_STREAMING_OFF_SOUND_ID;
  169. soundOn = LIVE_STREAMING_ON_SOUND_ID;
  170. }
  171. if (soundOff && soundOn) {
  172. dispatch(stopSound(soundOn));
  173. dispatch(playSound(soundOff));
  174. }
  175. if (typeof APP !== 'undefined') {
  176. APP.API.notifyRecordingStatusChanged(false, mode);
  177. }
  178. }
  179. }
  180. break;
  181. }
  182. }
  183. return result;
  184. });
  185. /**
  186. * Shows a notification about an error in the recording session. A
  187. * default notification will display if no error is specified in the passed
  188. * in recording session.
  189. *
  190. * @private
  191. * @param {Object} recorderSession - The recorder session model from the
  192. * lib.
  193. * @param {Dispatch} dispatch - The Redux Dispatch function.
  194. * @returns {void}
  195. */
  196. function _showRecordingErrorNotification(recorderSession, dispatch) {
  197. const mode = recorderSession.getMode();
  198. const error = recorderSession.getError();
  199. const isStreamMode = mode === JitsiMeetJS.constants.recording.mode.STREAM;
  200. switch (error) {
  201. case JitsiMeetJS.constants.recording.error.SERVICE_UNAVAILABLE:
  202. dispatch(showRecordingError({
  203. descriptionKey: 'recording.unavailable',
  204. descriptionArguments: {
  205. serviceName: isStreamMode
  206. ? '$t(liveStreaming.serviceName)'
  207. : '$t(recording.serviceName)'
  208. },
  209. titleKey: isStreamMode
  210. ? 'liveStreaming.unavailableTitle'
  211. : 'recording.unavailableTitle'
  212. }));
  213. break;
  214. case JitsiMeetJS.constants.recording.error.RESOURCE_CONSTRAINT:
  215. dispatch(showRecordingError({
  216. descriptionKey: isStreamMode
  217. ? 'liveStreaming.busy'
  218. : 'recording.busy',
  219. titleKey: isStreamMode
  220. ? 'liveStreaming.busyTitle'
  221. : 'recording.busyTitle'
  222. }));
  223. break;
  224. default:
  225. dispatch(showRecordingError({
  226. descriptionKey: isStreamMode
  227. ? 'liveStreaming.error'
  228. : 'recording.error',
  229. titleKey: isStreamMode
  230. ? 'liveStreaming.failedToStart'
  231. : 'recording.failedToStart'
  232. }));
  233. break;
  234. }
  235. if (typeof APP !== 'undefined') {
  236. APP.API.notifyRecordingStatusChanged(false, mode, error);
  237. }
  238. }