mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-05-14 13:37:51 +00:00
* fix: Drop duplicate call of wait for owner. * fix: Fixes leaking listeners while waiting for host to join. While waiting for the host to join on the dialog we attempt to join over and over again till we are admitted to enter the meeting. While doing that authRequired flag is on, and we were adding listeners on and on. * feat: Introduces conference join in progress action. This event is coming from lib-jitsi-meet and is fired when we receive the first presence of series when joining. It is always fired before joined event. * fix: Moves testing middleware to use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves follow-me middleware to use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves some polls logic to middleware and use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves reactions middleware to use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves recordings middleware to use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves shared-video middleware to use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves videosipgw middleware to use CONFERENCE_JOIN_IN_PROGRESS. * squash: Fix comments. * fix: Fixes join in progress on web. * fix: Moves variable extraction inside handlers. * fix: Moves variable extraction inside handlers again. * fix: Moves etherpad middleware to use CONFERENCE_JOIN_IN_PROGRESS.
283 lines
9.2 KiB
JavaScript
283 lines
9.2 KiB
JavaScript
/* @flow */
|
|
|
|
|
|
import {
|
|
createRecordingEvent,
|
|
sendAnalytics
|
|
} from '../analytics';
|
|
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
|
|
import { CONFERENCE_JOIN_IN_PROGRESS, getCurrentConference } from '../base/conference';
|
|
import JitsiMeetJS, {
|
|
JitsiConferenceEvents,
|
|
JitsiRecordingConstants
|
|
} from '../base/lib-jitsi-meet';
|
|
import { getParticipantDisplayName } from '../base/participants';
|
|
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
|
|
import {
|
|
playSound,
|
|
registerSound,
|
|
stopSound,
|
|
unregisterSound
|
|
} from '../base/sounds';
|
|
|
|
import { RECORDING_SESSION_UPDATED } from './actionTypes';
|
|
import {
|
|
clearRecordingSessions,
|
|
hidePendingRecordingNotification,
|
|
showPendingRecordingNotification,
|
|
showRecordingError,
|
|
showRecordingLimitNotification,
|
|
showRecordingWarning,
|
|
showStartedRecordingNotification,
|
|
showStoppedRecordingNotification,
|
|
updateRecordingSessionData
|
|
} from './actions';
|
|
import {
|
|
LIVE_STREAMING_OFF_SOUND_ID,
|
|
LIVE_STREAMING_ON_SOUND_ID,
|
|
RECORDING_OFF_SOUND_ID,
|
|
RECORDING_ON_SOUND_ID
|
|
} from './constants';
|
|
import { getSessionById, getResourceId } from './functions';
|
|
import {
|
|
LIVE_STREAMING_OFF_SOUND_FILE,
|
|
LIVE_STREAMING_ON_SOUND_FILE,
|
|
RECORDING_OFF_SOUND_FILE,
|
|
RECORDING_ON_SOUND_FILE
|
|
} from './sounds';
|
|
|
|
declare var APP: Object;
|
|
declare var interfaceConfig: Object;
|
|
|
|
/**
|
|
* StateListenerRegistry provides a reliable way to detect the leaving of a
|
|
* conference, where we need to clean up the recording sessions.
|
|
*/
|
|
StateListenerRegistry.register(
|
|
/* selector */ state => getCurrentConference(state),
|
|
/* listener */ (conference, { dispatch }) => {
|
|
if (!conference) {
|
|
dispatch(clearRecordingSessions());
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* The redux middleware to handle the recorder updates in a React way.
|
|
*
|
|
* @param {Store} store - The redux store.
|
|
* @returns {Function}
|
|
*/
|
|
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
|
let oldSessionData;
|
|
|
|
if (action.type === RECORDING_SESSION_UPDATED) {
|
|
oldSessionData
|
|
= getSessionById(getState(), action.sessionData.id);
|
|
}
|
|
|
|
const result = next(action);
|
|
|
|
switch (action.type) {
|
|
case APP_WILL_MOUNT:
|
|
dispatch(registerSound(
|
|
LIVE_STREAMING_OFF_SOUND_ID,
|
|
LIVE_STREAMING_OFF_SOUND_FILE));
|
|
|
|
dispatch(registerSound(
|
|
LIVE_STREAMING_ON_SOUND_ID,
|
|
LIVE_STREAMING_ON_SOUND_FILE));
|
|
|
|
dispatch(registerSound(
|
|
RECORDING_OFF_SOUND_ID,
|
|
RECORDING_OFF_SOUND_FILE));
|
|
|
|
dispatch(registerSound(
|
|
RECORDING_ON_SOUND_ID,
|
|
RECORDING_ON_SOUND_FILE));
|
|
|
|
break;
|
|
|
|
case APP_WILL_UNMOUNT:
|
|
dispatch(unregisterSound(LIVE_STREAMING_OFF_SOUND_ID));
|
|
dispatch(unregisterSound(LIVE_STREAMING_ON_SOUND_ID));
|
|
dispatch(unregisterSound(RECORDING_OFF_SOUND_ID));
|
|
dispatch(unregisterSound(RECORDING_ON_SOUND_ID));
|
|
|
|
break;
|
|
|
|
case CONFERENCE_JOIN_IN_PROGRESS: {
|
|
const { conference } = action;
|
|
|
|
conference.on(
|
|
JitsiConferenceEvents.RECORDER_STATE_CHANGED,
|
|
recorderSession => {
|
|
if (recorderSession) {
|
|
recorderSession.getID() && dispatch(updateRecordingSessionData(recorderSession));
|
|
recorderSession.getError() && _showRecordingErrorNotification(recorderSession, dispatch);
|
|
}
|
|
|
|
return;
|
|
});
|
|
|
|
break;
|
|
}
|
|
|
|
case RECORDING_SESSION_UPDATED: {
|
|
// When in recorder mode no notifications are shown
|
|
// or extra sounds are also not desired
|
|
// but we want to indicate those in case of sip gateway
|
|
const {
|
|
iAmRecorder,
|
|
iAmSipGateway,
|
|
recordingLimit
|
|
} = getState()['features/base/config'];
|
|
|
|
if (iAmRecorder && !iAmSipGateway) {
|
|
break;
|
|
}
|
|
|
|
const updatedSessionData
|
|
= getSessionById(getState(), action.sessionData.id);
|
|
const { initiator, mode, terminator } = updatedSessionData;
|
|
const { PENDING, OFF, ON } = JitsiRecordingConstants.status;
|
|
|
|
if (updatedSessionData.status === PENDING
|
|
&& (!oldSessionData || oldSessionData.status !== PENDING)) {
|
|
dispatch(showPendingRecordingNotification(mode));
|
|
} else if (updatedSessionData.status !== PENDING) {
|
|
dispatch(hidePendingRecordingNotification(mode));
|
|
|
|
if (updatedSessionData.status === ON
|
|
&& (!oldSessionData || oldSessionData.status !== ON)) {
|
|
if (typeof recordingLimit === 'object') {
|
|
// Show notification with additional information to the initiator.
|
|
dispatch(showRecordingLimitNotification(mode));
|
|
} else {
|
|
dispatch(showStartedRecordingNotification(mode, initiator, action.sessionData.id));
|
|
}
|
|
|
|
sendAnalytics(createRecordingEvent('start', mode));
|
|
|
|
let soundID;
|
|
|
|
if (mode === JitsiRecordingConstants.mode.FILE) {
|
|
soundID = RECORDING_ON_SOUND_ID;
|
|
} else if (mode === JitsiRecordingConstants.mode.STREAM) {
|
|
soundID = LIVE_STREAMING_ON_SOUND_ID;
|
|
}
|
|
|
|
if (soundID) {
|
|
dispatch(playSound(soundID));
|
|
}
|
|
|
|
if (typeof APP !== 'undefined') {
|
|
APP.API.notifyRecordingStatusChanged(true, mode);
|
|
}
|
|
} else if (updatedSessionData.status === OFF
|
|
&& (!oldSessionData || oldSessionData.status !== OFF)) {
|
|
if (terminator) {
|
|
dispatch(
|
|
showStoppedRecordingNotification(
|
|
mode, getParticipantDisplayName(getState, getResourceId(terminator))));
|
|
}
|
|
|
|
let duration = 0, soundOff, soundOn;
|
|
|
|
if (oldSessionData && oldSessionData.timestamp) {
|
|
duration
|
|
= (Date.now() / 1000) - oldSessionData.timestamp;
|
|
}
|
|
sendAnalytics(createRecordingEvent('stop', mode, duration));
|
|
|
|
if (mode === JitsiRecordingConstants.mode.FILE) {
|
|
soundOff = RECORDING_OFF_SOUND_ID;
|
|
soundOn = RECORDING_ON_SOUND_ID;
|
|
} else if (mode === JitsiRecordingConstants.mode.STREAM) {
|
|
soundOff = LIVE_STREAMING_OFF_SOUND_ID;
|
|
soundOn = LIVE_STREAMING_ON_SOUND_ID;
|
|
}
|
|
|
|
if (soundOff && soundOn) {
|
|
dispatch(stopSound(soundOn));
|
|
dispatch(playSound(soundOff));
|
|
}
|
|
|
|
if (typeof APP !== 'undefined') {
|
|
APP.API.notifyRecordingStatusChanged(false, mode);
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
});
|
|
|
|
/**
|
|
* Shows a notification about an error in the recording session. A
|
|
* default notification will display if no error is specified in the passed
|
|
* in recording session.
|
|
*
|
|
* @private
|
|
* @param {Object} recorderSession - The recorder session model from the
|
|
* lib.
|
|
* @param {Dispatch} dispatch - The Redux Dispatch function.
|
|
* @returns {void}
|
|
*/
|
|
function _showRecordingErrorNotification(recorderSession, dispatch) {
|
|
const mode = recorderSession.getMode();
|
|
const error = recorderSession.getError();
|
|
const isStreamMode = mode === JitsiMeetJS.constants.recording.mode.STREAM;
|
|
|
|
switch (error) {
|
|
case JitsiMeetJS.constants.recording.error.SERVICE_UNAVAILABLE:
|
|
dispatch(showRecordingError({
|
|
descriptionKey: 'recording.unavailable',
|
|
descriptionArguments: {
|
|
serviceName: isStreamMode
|
|
? '$t(liveStreaming.serviceName)'
|
|
: '$t(recording.serviceName)'
|
|
},
|
|
titleKey: isStreamMode
|
|
? 'liveStreaming.unavailableTitle'
|
|
: 'recording.unavailableTitle'
|
|
}));
|
|
break;
|
|
case JitsiMeetJS.constants.recording.error.RESOURCE_CONSTRAINT:
|
|
dispatch(showRecordingError({
|
|
descriptionKey: isStreamMode
|
|
? 'liveStreaming.busy'
|
|
: 'recording.busy',
|
|
titleKey: isStreamMode
|
|
? 'liveStreaming.busyTitle'
|
|
: 'recording.busyTitle'
|
|
}));
|
|
break;
|
|
case JitsiMeetJS.constants.recording.error.UNEXPECTED_REQUEST:
|
|
dispatch(showRecordingWarning({
|
|
descriptionKey: isStreamMode
|
|
? 'liveStreaming.sessionAlreadyActive'
|
|
: 'recording.sessionAlreadyActive',
|
|
titleKey: isStreamMode ? 'liveStreaming.inProgress' : 'recording.inProgress'
|
|
}));
|
|
break;
|
|
default:
|
|
dispatch(showRecordingError({
|
|
descriptionKey: isStreamMode
|
|
? 'liveStreaming.error'
|
|
: 'recording.error',
|
|
titleKey: isStreamMode
|
|
? 'liveStreaming.failedToStart'
|
|
: 'recording.failedToStart'
|
|
}));
|
|
break;
|
|
}
|
|
|
|
if (typeof APP !== 'undefined') {
|
|
APP.API.notifyRecordingStatusChanged(false, mode, error);
|
|
}
|
|
}
|