diff --git a/modules/API/API.js b/modules/API/API.js index 5d55dfd5c0c4..6c92395b47d8 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -8,16 +8,21 @@ import { sendAnalytics } from '../../react/features/analytics'; import { + getCurrentConference, sendTones, setPassword, setSubject } from '../../react/features/base/conference'; import { parseJWTFromURLParams } from '../../react/features/base/jwt'; +import { JitsiRecordingConstants } from '../../react/features/base/lib-jitsi-meet'; import { processExternalDeviceRequest } from '../../react/features/device-selection/functions'; +import { isEnabled as isDropboxEnabled } from '../../react/features/dropbox'; import { setE2EEKey } from '../../react/features/e2ee'; import { invite } from '../../react/features/invite'; +import { RECORDING_TYPES } from '../../react/features/recording/constants'; +import { getActiveSession } from '../../react/features/recording/functions'; import { muteAllParticipants } from '../../react/features/remote-video-menu/actions'; import { toggleTileView } from '../../react/features/video-layout'; import { setVideoQuality } from '../../react/features/video-quality'; @@ -190,6 +195,114 @@ function initCommands() { logger.debug('Set video quality command received'); sendAnalytics(createApiEvent('set.video.quality')); APP.store.dispatch(setVideoQuality(frameHeight)); + }, + + /** + * Starts a file recording or streaming depending on the passed on params. + * For youtube streams, `youtubeStreamKey` must be passed on. `youtubeBroadcastID` is optional. + * For dropbox recording, recording `mode` should be `file` and a dropbox oauth2 token must be provided. + * For file recording, recording `mode` should be `file` and optionally `shouldShare` could be passed on. + * No other params should be passed. + * + * @param { string } arg.mode - Recording mode, either `file` or `stream`. + * @param { string } arg.dropboxToken - Dropbox oauth2 token. + * @param { boolean } arg.shouldShare - Whether the recording should be shared with the participants or not. + * Only applies to certain jitsi meet deploys. + * @param { string } arg.youtubeStreamKey - The youtube stream key. + * @param { string } arg.youtubeBroadcastID - The youtube broacast ID. + * @returns {void} + */ + 'start-recording': ({ mode, dropboxToken, shouldShare, youtubeStreamKey, youtubeBroadcastID }) => { + const state = APP.store.getState(); + const conference = getCurrentConference(state); + + if (!conference) { + logger.error('Conference is not defined'); + + return; + } + + if (dropboxToken && !isDropboxEnabled(state)) { + logger.error('Failed starting recording: dropbox is not enabled on this deployment'); + + return; + } + + if (mode === JitsiRecordingConstants.mode.STREAM && !youtubeStreamKey) { + logger.error('Failed starting recording: missing youtube stream key'); + + return; + } + + let recordingConfig; + + if (mode === JitsiRecordingConstants.mode.FILE) { + if (dropboxToken) { + recordingConfig = { + mode: JitsiRecordingConstants.mode.FILE, + appData: JSON.stringify({ + 'file_recording_metadata': { + 'upload_credentials': { + 'service_name': RECORDING_TYPES.DROPBOX, + 'token': dropboxToken + } + } + }) + }; + } else { + recordingConfig = { + mode: JitsiRecordingConstants.mode.FILE, + appData: JSON.stringify({ + 'file_recording_metadata': { + 'share': shouldShare + } + }) + }; + } + } else if (mode === JitsiRecordingConstants.mode.STREAM) { + recordingConfig = { + broadcastId: youtubeBroadcastID, + mode: JitsiRecordingConstants.mode.STREAM, + streamId: youtubeStreamKey + }; + } else { + logger.error('Invalid recording mode provided'); + + return; + } + + conference.startRecording(recordingConfig); + }, + + /** + * Stops a recording or streaming in progress. + * + * @param {string} mode - `file` or `stream`. + * @returns {void} + */ + 'stop-recording': mode => { + const state = APP.store.getState(); + const conference = getCurrentConference(state); + + if (!conference) { + logger.error('Conference is not defined'); + + return; + } + + if (![ JitsiRecordingConstants.mode.FILE, JitsiRecordingConstants.mode.STREAM ].includes(mode)) { + logger.error('Invalid recording mode provided!'); + + return; + } + + const activeSession = getActiveSession(state, mode); + + if (activeSession && activeSession.id) { + conference.stopRecording(activeSession.id); + } else { + logger.error('No recording or streaming session found'); + } } }; transport.on('event', ({ data, name }) => { @@ -514,7 +627,8 @@ class API { notifyDeviceListChanged(devices: Object) { this._sendEvent({ name: 'device-list-changed', - devices }); + devices + }); } /** diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 347756964662..82ac2542ea3c 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -37,6 +37,8 @@ const commands = { sendEndpointTextMessage: 'send-endpoint-text-message', sendTones: 'send-tones', setVideoQuality: 'set-video-quality', + startRecording: 'start-recording', + stopRecording: 'stop-recording', subject: 'subject', submitFeedback: 'submit-feedback', toggleAudio: 'toggle-audio',