diff --git a/react/features/base/participants/functions.js b/react/features/base/participants/functions.js index f602aa2a1..3a4db5edb 100644 --- a/react/features/base/participants/functions.js +++ b/react/features/base/participants/functions.js @@ -180,6 +180,28 @@ export function getParticipantDisplayName( : 'Fellow Jitster'; } +/** + * Returns the presence status of a participant associated with the passed id. + * + * @param {(Function|Object)} stateful - The (whole) redux state, or redux's + * {@code getState} function to be used to retrieve the state. + * @param {string} id - The id of the participant. + * @returns {string} - The presence status. + */ +export function getParticipantPresenceStatus( + stateful: Object | Function, id: string) { + if (!id) { + return undefined; + } + const participantById = getParticipantById(stateful, id); + + if (!participantById) { + return undefined; + } + + return participantById.presence; +} + /** * Selectors for getting all known participants with fake participants filtered * out. diff --git a/react/features/invite/constants.js b/react/features/invite/constants.js index 97ea8b93f..61f686dd1 100644 --- a/react/features/invite/constants.js +++ b/react/features/invite/constants.js @@ -1,3 +1,21 @@ +/** + * The identifier of the sound to be played when the status of an outgoing call + * is expired. + * + * @type {string} + */ +export const OUTGOING_CALL_EXPIRED_SOUND_ID + = 'OUTGOING_CALL_EXPIRED_SOUND_ID'; + +/** + * The identifier of the sound to be played when the status of an outgoing call + * is rejected. + * + * @type {string} + */ +export const OUTGOING_CALL_REJECTED_SOUND_ID + = 'OUTGOING_CALL_REJECTED_SOUND_ID'; + /** * The identifier of the sound to be played when the status of an outgoing call * is ringing. diff --git a/react/features/invite/middleware.any.js b/react/features/invite/middleware.any.js index d51c3b3da..922197f51 100644 --- a/react/features/invite/middleware.any.js +++ b/react/features/invite/middleware.any.js @@ -2,9 +2,10 @@ import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app'; import { - getParticipantById, - PARTICIPANT_UPDATED, - PARTICIPANT_LEFT + getParticipantPresenceStatus, + PARTICIPANT_JOINED_SOUND_ID, + PARTICIPANT_LEFT, + PARTICIPANT_UPDATED } from '../base/participants'; import { MiddlewareRegistry } from '../base/redux'; import { @@ -15,24 +16,39 @@ import { } from '../base/sounds'; import { CALLING, + CONNECTED_USER, + EXPIRED, INVITED, + REJECTED, RINGING } from '../presence-status'; import { UPDATE_DIAL_IN_NUMBERS_FAILED } from './actionTypes'; import { - OUTGOING_CALL_START_SOUND_ID, - OUTGOING_CALL_RINGING_SOUND_ID + OUTGOING_CALL_EXPIRED_SOUND_ID, + OUTGOING_CALL_REJECTED_SOUND_ID, + OUTGOING_CALL_RINGING_SOUND_ID, + OUTGOING_CALL_START_SOUND_ID } from './constants'; -import { - OUTGOING_CALL_START_FILE, - OUTGOING_CALL_RINGING_FILE -} from './sounds'; +import { sounds } from './sounds'; const logger = require('jitsi-meet-logger').getLogger(__filename); declare var interfaceConfig: Object; +/** + * 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 +}; + /** * The middleware of the feature invite common to mobile/react-native and * Web/React. @@ -46,56 +62,55 @@ MiddlewareRegistry.register(store => next => action => { if (action.type === PARTICIPANT_UPDATED || action.type === PARTICIPANT_LEFT) { oldParticipantPresence - = _getParticipantPresence(store.getState(), action.participant.id); + = getParticipantPresenceStatus( + store.getState(), + action.participant.id); } const result = next(action); switch (action.type) { case APP_WILL_MOUNT: - store.dispatch( - registerSound( - OUTGOING_CALL_START_SOUND_ID, - OUTGOING_CALL_START_FILE)); - - store.dispatch( - registerSound( - OUTGOING_CALL_RINGING_SOUND_ID, - OUTGOING_CALL_RINGING_FILE, - { loop: true })); + for (const [ soundId, sound ] of sounds.entries()) { + store.dispatch(registerSound(soundId, sound.file, sound.options)); + } break; case APP_WILL_UNMOUNT: - store.dispatch(unregisterSound(OUTGOING_CALL_START_SOUND_ID)); - store.dispatch(unregisterSound(OUTGOING_CALL_RINGING_SOUND_ID)); + for (const soundId of sounds.keys()) { + store.dispatch(unregisterSound(soundId)); + } break; case PARTICIPANT_LEFT: case PARTICIPANT_UPDATED: { const newParticipantPresence - = _getParticipantPresence(store.getState(), action.participant.id); + = getParticipantPresenceStatus( + store.getState(), + action.participant.id); if (oldParticipantPresence === newParticipantPresence) { break; } - switch (oldParticipantPresence) { - case CALLING: - case INVITED: - store.dispatch(stopSound(OUTGOING_CALL_START_SOUND_ID)); - break; - case RINGING: - store.dispatch(stopSound(OUTGOING_CALL_RINGING_SOUND_ID)); + const oldSoundId + = oldParticipantPresence + && statusToRingtone[oldParticipantPresence]; + const newSoundId + = newParticipantPresence + && statusToRingtone[newParticipantPresence]; + + + if (oldSoundId === newSoundId) { break; } - switch (newParticipantPresence) { - case CALLING: - case INVITED: - store.dispatch(playSound(OUTGOING_CALL_START_SOUND_ID)); - break; - case RINGING: - store.dispatch(playSound(OUTGOING_CALL_RINGING_SOUND_ID)); + if (oldSoundId) { + store.dispatch(stopSound(oldSoundId)); + } + + if (newSoundId) { + store.dispatch(playSound(newSoundId)); } break; @@ -109,22 +124,3 @@ MiddlewareRegistry.register(store => next => action => { return result; }); - -/** - * Returns the presence status of a participant associated with the passed id. - * - * @param {Object} state - The redux state. - * @param {string} id - The id of the participant. - * @returns {string} - The presence status. - */ -function _getParticipantPresence(state, id) { - if (id) { - const participantById = getParticipantById(state, id); - - if (participantById) { - return participantById.presence; - } - } - - return undefined; -} diff --git a/react/features/invite/sounds.js b/react/features/invite/sounds.js index 43b512f04..b75e292bb 100644 --- a/react/features/invite/sounds.js +++ b/react/features/invite/sounds.js @@ -1,11 +1,44 @@ -/** - * The name of the sound file which will be played when the status of an - * outgoing call is ringing. - */ -export const OUTGOING_CALL_RINGING_FILE = 'outgoingRinging.wav'; +import { + OUTGOING_CALL_EXPIRED_SOUND_ID, + OUTGOING_CALL_REJECTED_SOUND_ID, + OUTGOING_CALL_RINGING_SOUND_ID, + OUTGOING_CALL_START_SOUND_ID +} from './constants'; /** - * The name of the sound file which will be played when outgoing call is - * started. + * Maps the sounds IDs with the filenames sounds associated with them. + * + * @type {Map} */ -export const OUTGOING_CALL_START_FILE = 'outgoingStart.wav'; +export const sounds = new Map([ + + /** + * The name of the sound file which will be played when outgoing call is + * expired. + */ + [ OUTGOING_CALL_EXPIRED_SOUND_ID, { file: 'rejected.wav' } ], + + /** + * The name of the sound file which will be played when outgoing call is + * rejected. + */ + [ OUTGOING_CALL_REJECTED_SOUND_ID, { file: 'rejected.wav' } ], + + /** + * The name of the sound file which will be played when the status of an + * outgoing call is ringing. + */ + [ + OUTGOING_CALL_RINGING_SOUND_ID, + { + file: 'outgoingRinging.wav', + options: { loop: true } + } + ], + + /** + * The name of the sound file which will be played when outgoing call is + * started. + */ + [ OUTGOING_CALL_START_SOUND_ID, { file: 'outgoingStart.wav' } ] +]); diff --git a/sounds/rejected.wav b/sounds/rejected.wav new file mode 100644 index 000000000..ab9fc1cd7 Binary files /dev/null and b/sounds/rejected.wav differ