fix(prosody-auth): Don't loose initial tracks.

When the prejoin screen is disabled during the prosody login cycle the initial GUM tracks were lost causing the user to start the call without local media and audio/video mute buttons staying forever in pending state.
pull/14904/head
Hristo Terezov 1 year ago
parent b4e4dd1aa9
commit 411e9a2372
  1. 35
      conference.js
  2. 24
      react/features/authentication/actions.web.ts
  3. 8
      react/features/authentication/components/web/LoginDialog.tsx
  4. 7
      react/features/authentication/middleware.ts
  5. 10
      react/features/base/media/actionTypes.ts
  6. 17
      react/features/base/media/actions.ts
  7. 31
      react/features/base/media/reducer.ts

@ -83,6 +83,7 @@ import {
setAudioAvailable,
setAudioMuted,
setAudioUnmutePermissions,
setInitialGUMPromise,
setVideoAvailable,
setVideoMuted,
setVideoUnmutePermissions
@ -606,6 +607,7 @@ export default {
return localTracks;
};
const { dispatch } = APP.store;
if (isPrejoinPageVisible(state)) {
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions);
@ -616,9 +618,9 @@ export default {
this._initDeviceList(true);
if (isPrejoinPageVisible(state)) {
APP.store.dispatch(gumPending([ MEDIA_TYPE.AUDIO, MEDIA_TYPE.VIDEO ], IGUMPendingState.NONE));
dispatch(gumPending([ MEDIA_TYPE.AUDIO, MEDIA_TYPE.VIDEO ], IGUMPendingState.NONE));
return APP.store.dispatch(initPrejoin(localTracks, errors));
return dispatch(initPrejoin(localTracks, errors));
}
logger.debug('Prejoin screen no longer displayed at the time when tracks were created');
@ -633,23 +635,28 @@ export default {
}
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions);
const gumPromise = tryCreateLocalTracks.then(tr => {
APP.store.dispatch(displayErrorsForCreateInitialLocalTracks(errors));
return Promise.all([
tryCreateLocalTracks.then(tr => {
APP.store.dispatch(displayErrorsForCreateInitialLocalTracks(errors));
return tr;
}).then(tr => {
this._initDeviceList(true);
return tr;
}).then(tr => {
this._initDeviceList(true);
const filteredTracks = handleInitialTracks(initialOptions, tr);
const filteredTracks = handleInitialTracks(initialOptions, tr);
setGUMPendingStateOnFailedTracks(filteredTracks, APP.store.dispatch);
setGUMPendingStateOnFailedTracks(filteredTracks, APP.store.dispatch);
return filteredTracks;
});
return filteredTracks;
}),
APP.store.dispatch(connect())
]).then(([ tracks, _ ]) => {
return Promise.all([
gumPromise,
dispatch(connect())
]).catch(e => {
dispatch(setInitialGUMPromise(gumPromise));
throw e;
})
.then(([ tracks, _ ]) => {
this.startConference(tracks).catch(logger.error);
});
},

@ -1,10 +1,13 @@
import { maybeRedirectToWelcomePage } from '../app/actions.web';
import { IStore } from '../app/types';
import { connect } from '../base/connection/actions.web';
import { openDialog } from '../base/dialog/actions';
import { browser } from '../base/lib-jitsi-meet';
import { setInitialGUMPromise } from '../base/media/actions';
import { CANCEL_LOGIN } from './actionTypes';
import LoginQuestionDialog from './components/web/LoginQuestionDialog';
import logger from './logger';
export * from './actions.any';
@ -76,3 +79,24 @@ export function openTokenAuthUrl(tokenAuthServiceUrl: string): any {
}
};
}
/**
* Executes connect with the passed credentials and then continues the flow to start a conference.
*
* @param {string} jid - The jid for the connection.
* @param {string} password - The password for the connection.
* @returns {Function}
*/
export function sumbitConnectionCredentials(jid?: string, password?: string) {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const { initialGUMPromise } = getState()['features/base/media'].common;
dispatch(connect(jid, password))
.then(() => initialGUMPromise ?? [])
.then((tracks: Array<Object> = []) => {
// clear the initial GUM promise since we don't need it anymore.
dispatch(setInitialGUMPromise());
APP.conference.startConference(tracks).catch(logger.error);
});
};
}

@ -10,10 +10,10 @@ import { translate, translateToHTML } from '../../../base/i18n/functions';
import { JitsiConnectionErrors } from '../../../base/lib-jitsi-meet';
import Dialog from '../../../base/ui/components/web/Dialog';
import Input from '../../../base/ui/components/web/Input';
import { joinConference } from '../../../prejoin/actions.web';
import {
authenticateAndUpgradeRole,
cancelLogin
cancelLogin,
sumbitConnectionCredentials
} from '../../actions.web';
/**
@ -134,9 +134,7 @@ class LoginDialog extends Component<IProps, IState> {
if (conference) {
dispatch(authenticateAndUpgradeRole(jid, password, conference));
} else {
// dispatch(connect(jid, password));
// FIXME: Workaround for the web version. To be removed once we get rid of conference.js
dispatch(joinConference(undefined, false, jid, password));
dispatch(sumbitConnectionCredentials(jid, password));
}
}

@ -13,6 +13,7 @@ import {
JitsiConferenceErrors,
JitsiConnectionErrors
} from '../base/lib-jitsi-meet';
import { setInitialGUMPromise } from '../base/media/actions';
import { MEDIA_TYPE } from '../base/media/constants';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { isLocalTrackMuted } from '../base/tracks/functions.any';
@ -153,6 +154,8 @@ MiddlewareRegistry.register(store => next => action => {
error.recoverable = true;
_handleLogin(store);
} else {
store.dispatch(setInitialGUMPromise());
}
break;
@ -264,6 +267,8 @@ function _handleLogin({ dispatch, getState }: IStore) {
const videoMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.VIDEO);
if (!room) {
dispatch(setInitialGUMPromise());
logger.warn('Cannot handle login, room is undefined!');
return;
@ -275,6 +280,8 @@ function _handleLogin({ dispatch, getState }: IStore) {
return;
}
dispatch(setInitialGUMPromise());
getTokenAuthUrl(
config,
locationURL,

@ -51,6 +51,16 @@ export const SET_AUDIO_UNMUTE_PERMISSIONS = 'SET_AUDIO_UNMUTE_PERMISSIONS';
*/
export const SET_CAMERA_FACING_MODE = 'SET_CAMERA_FACING_MODE';
/**
* Sets the initial GUM promise.
*
* {
* type: SET_INITIAL_GUM_PROMISE,
* promise: Promise
* }}
*/
export const SET_INITIAL_GUM_PROMISE = 'SET_INITIAL_GUM_PROMISE';
/**
* The type of (redux) action to set the muted state of the local screenshare.
*

@ -9,6 +9,7 @@ import {
SET_AUDIO_MUTED,
SET_AUDIO_UNMUTE_PERMISSIONS,
SET_CAMERA_FACING_MODE,
SET_INITIAL_GUM_PROMISE,
SET_SCREENSHARE_MUTED,
SET_VIDEO_AVAILABLE,
SET_VIDEO_MUTED,
@ -93,6 +94,22 @@ export function setCameraFacingMode(cameraFacingMode: string) {
};
}
/**
* Sets the initial GUM promise.
*
* @param {Promise<Array<Object>> | undefined} promise - The promise.
* @returns {{
* type: SET_INITIAL_GUM_PROMISE,
* promise: Promise
* }}
*/
export function setInitialGUMPromise(promise?: Promise<Array<Object>>) {
return {
type: SET_INITIAL_GUM_PROMISE,
promise
};
}
/**
* Action to set the muted state of the local screenshare.
*

@ -10,6 +10,7 @@ import {
SET_AUDIO_MUTED,
SET_AUDIO_UNMUTE_PERMISSIONS,
SET_CAMERA_FACING_MODE,
SET_INITIAL_GUM_PROMISE,
SET_SCREENSHARE_MUTED,
SET_VIDEO_AVAILABLE,
SET_VIDEO_MUTED,
@ -87,6 +88,30 @@ function _audio(state: IAudioState = _AUDIO_INITIAL_MEDIA_STATE, action: AnyActi
}
}
/**
* The initial common media state.
*/
const _COMMON_INITIAL_STATE = {};
/**
* Reducer fot the common properties in media state.
*
* @param {ICommonState} state - Common media state.
* @param {Object} action - Action object.
* @param {string} action.type - Type of action.
* @returns {ICommonState}
*/
function _common(state: ICommonState = _COMMON_INITIAL_STATE, action: AnyAction) {
if (action.type === SET_INITIAL_GUM_PROMISE) {
return {
...state,
initialGUMPromise: action.promise
};
}
return state;
}
/**
* Media state object for local screenshare.
*
@ -247,6 +272,10 @@ interface IAudioState {
unmuteBlocked: boolean;
}
interface ICommonState {
initialGUMPromise?: Promise<Array<Object>>;
}
interface IScreenshareState {
available: boolean;
muted: number;
@ -264,6 +293,7 @@ interface IVideoState {
export interface IMediaState {
audio: IAudioState;
common: ICommonState;
screenshare: IScreenshareState;
video: IVideoState;
}
@ -280,6 +310,7 @@ export interface IMediaState {
*/
ReducerRegistry.register<IMediaState>('features/base/media', combineReducers({
audio: _audio,
common: _common,
screenshare: _screenshare,
video: _video
}));

Loading…
Cancel
Save