2018-05-01 04:43:47 +00:00
|
|
|
// @flow
|
|
|
|
|
2018-07-11 09:42:43 +00:00
|
|
|
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
|
2018-05-16 15:03:10 +00:00
|
|
|
import {
|
2018-06-26 22:56:22 +00:00
|
|
|
CONFERENCE_JOINED
|
|
|
|
} from '../base/conference';
|
|
|
|
import {
|
|
|
|
getLocalParticipant,
|
2018-05-21 20:52:30 +00:00
|
|
|
getParticipantPresenceStatus,
|
2018-06-26 22:56:22 +00:00
|
|
|
getParticipants,
|
2018-05-21 21:40:15 +00:00
|
|
|
PARTICIPANT_JOINED,
|
2018-05-21 20:52:30 +00:00
|
|
|
PARTICIPANT_JOINED_SOUND_ID,
|
|
|
|
PARTICIPANT_LEFT,
|
2018-06-26 22:56:22 +00:00
|
|
|
PARTICIPANT_UPDATED,
|
|
|
|
pinParticipant
|
2018-05-16 15:03:10 +00:00
|
|
|
} from '../base/participants';
|
2017-05-19 22:35:10 +00:00
|
|
|
import { MiddlewareRegistry } from '../base/redux';
|
2018-05-16 15:03:10 +00:00
|
|
|
import {
|
|
|
|
playSound,
|
|
|
|
registerSound,
|
|
|
|
stopSound,
|
|
|
|
unregisterSound
|
|
|
|
} from '../base/sounds';
|
|
|
|
import {
|
|
|
|
CALLING,
|
2018-05-21 20:52:30 +00:00
|
|
|
CONNECTED_USER,
|
|
|
|
EXPIRED,
|
2018-05-16 15:03:10 +00:00
|
|
|
INVITED,
|
2018-05-21 20:52:30 +00:00
|
|
|
REJECTED,
|
2018-05-16 15:03:10 +00:00
|
|
|
RINGING
|
|
|
|
} from '../presence-status';
|
2017-05-19 22:35:10 +00:00
|
|
|
|
2018-06-26 22:56:22 +00:00
|
|
|
import {
|
|
|
|
SET_CALLEE_INFO_VISIBLE,
|
|
|
|
UPDATE_DIAL_IN_NUMBERS_FAILED
|
|
|
|
} from './actionTypes';
|
|
|
|
import {
|
|
|
|
invite,
|
|
|
|
removePendingInviteRequests,
|
|
|
|
setCalleeInfoVisible
|
|
|
|
} from './actions';
|
2018-05-16 15:03:10 +00:00
|
|
|
import {
|
2018-05-21 20:52:30 +00:00
|
|
|
OUTGOING_CALL_EXPIRED_SOUND_ID,
|
|
|
|
OUTGOING_CALL_REJECTED_SOUND_ID,
|
|
|
|
OUTGOING_CALL_RINGING_SOUND_ID,
|
|
|
|
OUTGOING_CALL_START_SOUND_ID
|
2018-05-16 15:03:10 +00:00
|
|
|
} from './constants';
|
2018-05-21 20:52:30 +00:00
|
|
|
import { sounds } from './sounds';
|
2017-05-19 22:35:10 +00:00
|
|
|
|
|
|
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
|
|
|
|
2018-05-16 15:03:10 +00:00
|
|
|
declare var interfaceConfig: Object;
|
|
|
|
|
2018-05-21 20:52:30 +00:00
|
|
|
/**
|
|
|
|
* Maps the presence status with the ID of the sound that will be played when
|
|
|
|
* the status is received.
|
|
|
|
*/
|
|
|
|
const statusToRingtone = {
|
|
|
|
[CALLING]: OUTGOING_CALL_START_SOUND_ID,
|
|
|
|
[CONNECTED_USER]: PARTICIPANT_JOINED_SOUND_ID,
|
|
|
|
[EXPIRED]: OUTGOING_CALL_EXPIRED_SOUND_ID,
|
|
|
|
[INVITED]: OUTGOING_CALL_START_SOUND_ID,
|
|
|
|
[REJECTED]: OUTGOING_CALL_REJECTED_SOUND_ID,
|
|
|
|
[RINGING]: OUTGOING_CALL_RINGING_SOUND_ID
|
|
|
|
};
|
|
|
|
|
2017-05-19 22:35:10 +00:00
|
|
|
/**
|
2018-05-01 04:43:47 +00:00
|
|
|
* The middleware of the feature invite common to mobile/react-native and
|
|
|
|
* Web/React.
|
2017-05-19 22:35:10 +00:00
|
|
|
*
|
2018-05-01 04:43:47 +00:00
|
|
|
* @param {Store} store - The redux store.
|
2017-05-19 22:35:10 +00:00
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
MiddlewareRegistry.register(store => next => action => {
|
2018-05-16 15:03:10 +00:00
|
|
|
let oldParticipantPresence;
|
2018-06-26 22:56:22 +00:00
|
|
|
const { dispatch, getState } = store;
|
|
|
|
const state = getState();
|
2018-05-16 15:03:10 +00:00
|
|
|
|
|
|
|
if (action.type === PARTICIPANT_UPDATED
|
|
|
|
|| action.type === PARTICIPANT_LEFT) {
|
|
|
|
oldParticipantPresence
|
2018-06-26 22:56:22 +00:00
|
|
|
= getParticipantPresenceStatus(state, action.participant.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action.type === SET_CALLEE_INFO_VISIBLE) {
|
|
|
|
if (action.calleeInfoVisible) {
|
|
|
|
dispatch(pinParticipant(getLocalParticipant(state).id));
|
|
|
|
} else {
|
|
|
|
// unpin participant
|
|
|
|
dispatch(pinParticipant());
|
|
|
|
}
|
2018-05-16 15:03:10 +00:00
|
|
|
}
|
|
|
|
|
2017-05-19 22:35:10 +00:00
|
|
|
const result = next(action);
|
|
|
|
|
|
|
|
switch (action.type) {
|
2018-05-16 15:03:10 +00:00
|
|
|
case APP_WILL_MOUNT:
|
2018-05-21 20:52:30 +00:00
|
|
|
for (const [ soundId, sound ] of sounds.entries()) {
|
2018-06-26 22:56:22 +00:00
|
|
|
dispatch(registerSound(soundId, sound.file, sound.options));
|
2018-05-21 20:52:30 +00:00
|
|
|
}
|
2018-05-16 15:03:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case APP_WILL_UNMOUNT:
|
2018-05-21 20:52:30 +00:00
|
|
|
for (const soundId of sounds.keys()) {
|
2018-06-26 22:56:22 +00:00
|
|
|
dispatch(unregisterSound(soundId));
|
2018-05-21 20:52:30 +00:00
|
|
|
}
|
2018-05-16 15:03:10 +00:00
|
|
|
break;
|
|
|
|
|
2018-06-26 22:56:22 +00:00
|
|
|
case CONFERENCE_JOINED:
|
|
|
|
_onConferenceJoined(store);
|
|
|
|
break;
|
|
|
|
|
2018-05-21 21:40:15 +00:00
|
|
|
case PARTICIPANT_JOINED:
|
2018-05-16 15:03:10 +00:00
|
|
|
case PARTICIPANT_LEFT:
|
|
|
|
case PARTICIPANT_UPDATED: {
|
2018-06-26 22:56:22 +00:00
|
|
|
_maybeHideCalleeInfo(action, store);
|
|
|
|
|
2018-05-16 15:03:10 +00:00
|
|
|
const newParticipantPresence
|
2018-06-26 22:56:22 +00:00
|
|
|
= getParticipantPresenceStatus(state, action.participant.id);
|
2018-05-16 15:03:10 +00:00
|
|
|
|
|
|
|
if (oldParticipantPresence === newParticipantPresence) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-05-21 20:52:30 +00:00
|
|
|
const oldSoundId
|
|
|
|
= oldParticipantPresence
|
|
|
|
&& statusToRingtone[oldParticipantPresence];
|
|
|
|
const newSoundId
|
|
|
|
= newParticipantPresence
|
|
|
|
&& statusToRingtone[newParticipantPresence];
|
|
|
|
|
|
|
|
|
|
|
|
if (oldSoundId === newSoundId) {
|
2018-05-16 15:03:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-05-21 20:52:30 +00:00
|
|
|
if (oldSoundId) {
|
2018-06-26 22:56:22 +00:00
|
|
|
dispatch(stopSound(oldSoundId));
|
2018-05-21 20:52:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (newSoundId) {
|
2018-06-26 22:56:22 +00:00
|
|
|
dispatch(playSound(newSoundId));
|
2018-05-16 15:03:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2017-05-19 22:35:10 +00:00
|
|
|
case UPDATE_DIAL_IN_NUMBERS_FAILED:
|
2017-06-15 00:40:51 +00:00
|
|
|
logger.error(
|
|
|
|
'Error encountered while fetching dial-in numbers:',
|
|
|
|
action.error);
|
2017-05-19 22:35:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
});
|
2018-06-26 22:56:22 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Hides the callee info layot if there are more than 1 real
|
|
|
|
* (not poltergeist, shared video, etc.) participants in the call.
|
|
|
|
*
|
|
|
|
* @param {Object} action - The redux action.
|
|
|
|
* @param {ReduxStore} store - The redux store.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
function _maybeHideCalleeInfo(action, store) {
|
|
|
|
const state = store.getState();
|
|
|
|
|
|
|
|
if (!state['features/invite'].calleeInfoVisible) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const participants = getParticipants(state);
|
|
|
|
const numberOfPoltergeists
|
|
|
|
= participants.filter(p => p.botType === 'poltergeist').length;
|
|
|
|
const numberOfRealParticipants = participants.length - numberOfPoltergeists;
|
|
|
|
|
|
|
|
if ((numberOfPoltergeists > 1 || numberOfRealParticipants > 1)
|
|
|
|
|| (action.type === PARTICIPANT_LEFT && participants.length === 1)) {
|
|
|
|
store.dispatch(setCalleeInfoVisible(false));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Executes the pending invitation requests if any.
|
|
|
|
*
|
|
|
|
* @param {ReduxStore} store - The redux store.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
function _onConferenceJoined(store) {
|
|
|
|
const { dispatch, getState } = store;
|
|
|
|
|
|
|
|
const pendingInviteRequests
|
|
|
|
= getState()['features/invite'].pendingInviteRequests || [];
|
|
|
|
|
|
|
|
pendingInviteRequests.forEach(({ invitees, callback }) => {
|
|
|
|
dispatch(invite(invitees))
|
|
|
|
.then(failedInvitees => {
|
|
|
|
callback(failedInvitees);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
dispatch(removePendingInviteRequests());
|
|
|
|
}
|