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.

actions.any.js 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // @flow
  2. import { getMeetingRegion, getRecordingSharingUrl } from '../base/config';
  3. import JitsiMeetJS, { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
  4. import { getLocalParticipant, getParticipantDisplayName } from '../base/participants';
  5. import { copyText } from '../base/util/helpers';
  6. import { getVpaasTenant, isVpaasMeeting } from '../jaas/functions';
  7. import {
  8. NOTIFICATION_TIMEOUT_TYPE,
  9. hideNotification,
  10. showErrorNotification,
  11. showNotification,
  12. showWarningNotification
  13. } from '../notifications';
  14. import {
  15. CLEAR_RECORDING_SESSIONS,
  16. RECORDING_SESSION_UPDATED,
  17. SET_PENDING_RECORDING_NOTIFICATION_UID,
  18. SET_SELECTED_RECORDING_SERVICE,
  19. SET_STREAM_KEY
  20. } from './actionTypes';
  21. import { getRecordingLink, getResourceId, isSavingRecordingOnDropbox } from './functions';
  22. import logger from './logger';
  23. declare var APP: Object;
  24. /**
  25. * Clears the data of every recording sessions.
  26. *
  27. * @returns {{
  28. * type: CLEAR_RECORDING_SESSIONS
  29. * }}
  30. */
  31. export function clearRecordingSessions() {
  32. return {
  33. type: CLEAR_RECORDING_SESSIONS
  34. };
  35. }
  36. /**
  37. * Signals that the pending recording notification should be removed from the
  38. * screen.
  39. *
  40. * @param {string} streamType - The type of the stream ({@code 'file'} or
  41. * {@code 'stream'}).
  42. * @returns {Function}
  43. */
  44. export function hidePendingRecordingNotification(streamType: string) {
  45. return (dispatch: Function, getState: Function) => {
  46. const { pendingNotificationUids } = getState()['features/recording'];
  47. const pendingNotificationUid = pendingNotificationUids[streamType];
  48. if (pendingNotificationUid) {
  49. dispatch(hideNotification(pendingNotificationUid));
  50. dispatch(
  51. _setPendingRecordingNotificationUid(
  52. undefined, streamType));
  53. }
  54. };
  55. }
  56. /**
  57. * Sets the stream key last used by the user for later reuse.
  58. *
  59. * @param {string} streamKey - The stream key to set.
  60. * @returns {{
  61. * type: SET_STREAM_KEY,
  62. * streamKey: string
  63. * }}
  64. */
  65. export function setLiveStreamKey(streamKey: string) {
  66. return {
  67. type: SET_STREAM_KEY,
  68. streamKey
  69. };
  70. }
  71. /**
  72. * Signals that the pending recording notification should be shown on the
  73. * screen.
  74. *
  75. * @param {string} streamType - The type of the stream ({@code file} or
  76. * {@code stream}).
  77. * @returns {Function}
  78. */
  79. export function showPendingRecordingNotification(streamType: string) {
  80. return async (dispatch: Function) => {
  81. const isLiveStreaming
  82. = streamType === JitsiMeetJS.constants.recording.mode.STREAM;
  83. const dialogProps = isLiveStreaming ? {
  84. descriptionKey: 'liveStreaming.pending',
  85. titleKey: 'dialog.liveStreaming'
  86. } : {
  87. descriptionKey: 'recording.pending',
  88. titleKey: 'dialog.recording'
  89. };
  90. const notification = await dispatch(showNotification({
  91. isDismissAllowed: false,
  92. ...dialogProps
  93. }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
  94. if (notification) {
  95. dispatch(_setPendingRecordingNotificationUid(notification.uid, streamType));
  96. }
  97. };
  98. }
  99. /**
  100. * Signals that the recording error notification should be shown.
  101. *
  102. * @param {Object} props - The Props needed to render the notification.
  103. * @returns {showErrorNotification}
  104. */
  105. export function showRecordingError(props: Object) {
  106. return showErrorNotification(props, NOTIFICATION_TIMEOUT_TYPE.LONG);
  107. }
  108. /**
  109. * Signals that the recording warning notification should be shown.
  110. *
  111. * @param {Object} props - The Props needed to render the notification.
  112. * @returns {showWarningNotification}
  113. */
  114. export function showRecordingWarning(props: Object) {
  115. return showWarningNotification(props);
  116. }
  117. /**
  118. * Signals that the stopped recording notification should be shown on the
  119. * screen for a given period.
  120. *
  121. * @param {string} streamType - The type of the stream ({@code file} or
  122. * {@code stream}).
  123. * @param {string?} participantName - The participant name stopping the recording.
  124. * @returns {showNotification}
  125. */
  126. export function showStoppedRecordingNotification(streamType: string, participantName?: string) {
  127. const isLiveStreaming
  128. = streamType === JitsiMeetJS.constants.recording.mode.STREAM;
  129. const descriptionArguments = { name: participantName };
  130. const dialogProps = isLiveStreaming ? {
  131. descriptionKey: participantName ? 'liveStreaming.offBy' : 'liveStreaming.off',
  132. descriptionArguments,
  133. titleKey: 'dialog.liveStreaming'
  134. } : {
  135. descriptionKey: participantName ? 'recording.offBy' : 'recording.off',
  136. descriptionArguments,
  137. titleKey: 'dialog.recording'
  138. };
  139. return showNotification(dialogProps, NOTIFICATION_TIMEOUT_TYPE.SHORT);
  140. }
  141. /**
  142. * Signals that a started recording notification should be shown on the
  143. * screen for a given period.
  144. *
  145. * @param {string} mode - The type of the recording: Stream of File.
  146. * @param {string | Object } initiator - The participant who started recording.
  147. * @param {string} sessionId - The recording session id.
  148. * @returns {Function}
  149. */
  150. export function showStartedRecordingNotification(
  151. mode: string,
  152. initiator: Object | string,
  153. sessionId: string) {
  154. return async (dispatch: Function, getState: Function) => {
  155. const state = getState();
  156. const initiatorId = getResourceId(initiator);
  157. const participantName = getParticipantDisplayName(state, initiatorId);
  158. let dialogProps = {
  159. customActionNameKey: undefined,
  160. descriptionKey: participantName ? 'liveStreaming.onBy' : 'liveStreaming.on',
  161. descriptionArguments: { name: participantName },
  162. isDismissAllowed: true,
  163. titleKey: 'dialog.liveStreaming'
  164. };
  165. if (mode !== JitsiMeetJS.constants.recording.mode.STREAM) {
  166. const recordingSharingUrl = getRecordingSharingUrl(state);
  167. const iAmRecordingInitiator = getLocalParticipant(state).id === initiatorId;
  168. dialogProps = {
  169. customActionHandler: undefined,
  170. customActionNameKey: undefined,
  171. descriptionKey: participantName ? 'recording.onBy' : 'recording.on',
  172. descriptionArguments: { name: participantName },
  173. isDismissAllowed: true,
  174. titleKey: 'dialog.recording'
  175. };
  176. // fetch the recording link from the server for recording initiators in jaas meetings
  177. if (recordingSharingUrl
  178. && isVpaasMeeting(state)
  179. && iAmRecordingInitiator
  180. && !isSavingRecordingOnDropbox(state)) {
  181. const region = getMeetingRegion(state);
  182. const tenant = getVpaasTenant(state);
  183. try {
  184. const link = await getRecordingLink(recordingSharingUrl, sessionId, region, tenant);
  185. if (typeof APP === 'object') {
  186. APP.API.notifyRecordingLinkAvailable(link);
  187. }
  188. // add the option to copy recording link
  189. dialogProps.customActionNameKey = 'recording.copyLink';
  190. dialogProps.customActionHandler = () => copyText(link);
  191. dialogProps.titleKey = 'recording.on';
  192. dialogProps.descriptionKey = 'recording.linkGenerated';
  193. dialogProps.isDismissAllowed = false;
  194. } catch (err) {
  195. dispatch(showErrorNotification({
  196. titleKey: 'recording.errorFetchingLink'
  197. }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
  198. return logger.error('Could not fetch recording link', err);
  199. }
  200. }
  201. }
  202. dispatch(showNotification(dialogProps, NOTIFICATION_TIMEOUT_TYPE.SHORT));
  203. };
  204. }
  205. /**
  206. * Updates the known state for a given recording session.
  207. *
  208. * @param {Object} session - The new state to merge with the existing state in
  209. * redux.
  210. * @returns {{
  211. * type: RECORDING_SESSION_UPDATED,
  212. * sessionData: Object
  213. * }}
  214. */
  215. export function updateRecordingSessionData(session: Object) {
  216. const status = session.getStatus();
  217. const timestamp
  218. = status === JitsiRecordingConstants.status.ON
  219. ? Date.now() / 1000
  220. : undefined;
  221. return {
  222. type: RECORDING_SESSION_UPDATED,
  223. sessionData: {
  224. error: session.getError(),
  225. id: session.getID(),
  226. initiator: session.getInitiator(),
  227. liveStreamViewURL: session.getLiveStreamViewURL(),
  228. mode: session.getMode(),
  229. status,
  230. terminator: session.getTerminator(),
  231. timestamp
  232. }
  233. };
  234. }
  235. /**
  236. * Sets the selected recording service.
  237. *
  238. * @param {string} selectedRecordingService - The new selected recording service.
  239. * @returns {Object}
  240. */
  241. export function setSelectedRecordingService(selectedRecordingService: string) {
  242. return {
  243. type: SET_SELECTED_RECORDING_SERVICE,
  244. selectedRecordingService
  245. };
  246. }
  247. /**
  248. * Sets UID of the the pending streaming notification to use it when hinding
  249. * the notification is necessary, or unsets it when undefined (or no param) is
  250. * passed.
  251. *
  252. * @param {?number} uid - The UID of the notification.
  253. * @param {string} streamType - The type of the stream ({@code file} or
  254. * {@code stream}).
  255. * @returns {{
  256. * type: SET_PENDING_RECORDING_NOTIFICATION_UID,
  257. * streamType: string,
  258. * uid: number
  259. * }}
  260. */
  261. function _setPendingRecordingNotificationUid(uid: ?number, streamType: string) {
  262. return {
  263. type: SET_PENDING_RECORDING_NOTIFICATION_UID,
  264. streamType,
  265. uid
  266. };
  267. }