Sfoglia il codice sorgente

fix(prejoin): Prevent double joining conference.

master
Hristo Terezov 3 anni fa
parent
commit
2a725d2165

+ 10
- 3
conference.js Vedi File

@@ -129,7 +129,8 @@ import {
129 129
     initPrejoin,
130 130
     isPrejoinPageEnabled,
131 131
     isPrejoinPageVisible,
132
-    makePrecallTest
132
+    makePrecallTest,
133
+    setJoiningInProgress
133 134
 } from './react/features/prejoin';
134 135
 import { disableReceiver, stopReceiver } from './react/features/remote-control';
135 136
 import { setScreenAudioShareState, isScreenAudioShared } from './react/features/screen-share/';
@@ -861,9 +862,15 @@ export default {
861 862
             _onConnectionPromiseCreated = undefined;
862 863
         }
863 864
 
864
-        const con = await _connectionPromise;
865
+        let con;
865 866
 
866
-        this.startConference(con, tracks);
867
+        try {
868
+            con = await _connectionPromise;
869
+            this.startConference(con, tracks);
870
+        } catch (error) {
871
+            logger.error(`An error occurred while trying to join a meeting from the prejoin screen: ${error}`);
872
+            APP.store.dispatch(setJoiningInProgress(false));
873
+        }
867 874
     },
868 875
 
869 876
     /**

+ 2
- 2
react/features/prejoin/actionTypes.js Vedi File

@@ -1,8 +1,8 @@
1 1
 
2 2
 /**
3
- * Action type to signal the start of the conference.
3
+ * Action type to signal that joining is in progress.
4 4
  */
5
-export const PREJOIN_START_CONFERENCE = 'PREJOIN_START_CONFERENCE';
5
+export const PREJOIN_JOINING_IN_PROGRESS = 'PREJOIN_JOINING_IN_PROGRESS';
6 6
 
7 7
 /**
8 8
  * Action type to signal that prejoin page was initialized.

+ 88
- 13
react/features/prejoin/actions.js Vedi File

@@ -1,27 +1,30 @@
1 1
 // @flow
2 2
 
3 3
 declare var JitsiMeetJS: Object;
4
+declare var APP: Object;
4 5
 
5 6
 import uuid from 'uuid';
6 7
 
7
-import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions';
8
+import { getDialOutStatusUrl, getDialOutUrl, updateConfig } from '../base/config';
9
+import { isIosMobileBrowser } from '../base/environment/utils';
8 10
 import { createLocalTrack } from '../base/lib-jitsi-meet';
9
-import { isVideoMutedByUser } from '../base/media';
11
+import { isVideoMutedByUser, MEDIA_TYPE } from '../base/media';
12
+import { updateSettings } from '../base/settings';
10 13
 import {
14
+    createLocalTracksF,
11 15
     getLocalAudioTrack,
16
+    getLocalTracks,
12 17
     getLocalVideoTrack,
13 18
     trackAdded,
14 19
     replaceLocalTrack
15 20
 } from '../base/tracks';
16
-import { createLocalTracksF } from '../base/tracks/functions';
17 21
 import { openURLInBrowser } from '../base/util';
18 22
 import { executeDialOutRequest, executeDialOutStatusRequest, getDialInfoPageURL } from '../invite/functions';
19 23
 import { showErrorNotification } from '../notifications';
20 24
 
21 25
 import {
26
+    PREJOIN_JOINING_IN_PROGRESS,
22 27
     PREJOIN_INITIALIZED,
23
-    PREJOIN_START_CONFERENCE,
24
-    SET_DEVICE_STATUS,
25 28
     SET_DIALOUT_COUNTRY,
26 29
     SET_DIALOUT_NUMBER,
27 30
     SET_DIALOUT_STATUS,
@@ -31,9 +34,10 @@ import {
31 34
     SET_JOIN_BY_PHONE_DIALOG_VISIBLITY,
32 35
     SET_PRECALL_TEST_RESULTS,
33 36
     SET_PREJOIN_DEVICE_ERRORS,
34
-    SET_PREJOIN_PAGE_VISIBILITY
37
+    SET_PREJOIN_PAGE_VISIBILITY,
38
+    SET_DEVICE_STATUS
35 39
 } from './actionTypes';
36
-import { type PREJOIN_SCREEN_STATE } from './constants';
40
+import { type PREJOIN_SCREEN_STATE, PREJOIN_SCREEN_STATES } from './constants';
37 41
 import {
38 42
     getFullDialOutNumber,
39 43
     getDialOutConferenceUrl,
@@ -209,15 +213,74 @@ export function initPrejoin(tracks: Object[], errors: Object) {
209 213
  * Action used to start the conference.
210 214
  *
211 215
  * @param {Object} options - The config options that override the default ones (if any).
216
+ * @param {boolean} ignoreJoiningInProgress - If true we won't check the joiningInProgress flag.
212 217
  * @returns {Function}
213 218
  */
214
-export function joinConference(options?: Object) {
219
+export function joinConference(options?: Object, ignoreJoiningInProgress: boolean = false) {
220
+    return async function(dispatch: Function, getState: Function) {
221
+        if (!ignoreJoiningInProgress) {
222
+            const state = getState();
223
+            const { joiningInProgress } = state['features/prejoin'];
224
+
225
+            if (joiningInProgress) {
226
+                return;
227
+            }
228
+
229
+            dispatch(setJoiningInProgress(true));
230
+        }
231
+
232
+        const state = getState();
233
+        const { userSelectedSkipPrejoin } = state['features/prejoin'];
234
+        let localTracks = getLocalTracks(state['features/base/tracks']);
235
+
236
+        options && dispatch(updateConfig(options));
237
+
238
+        userSelectedSkipPrejoin && dispatch(updateSettings({
239
+            userSelectedSkipPrejoin
240
+        }));
241
+
242
+        // Do not signal audio/video tracks if the user joins muted.
243
+        for (const track of localTracks) {
244
+            // Always add the audio track on mobile Safari because of a known issue where audio playout doesn't happen
245
+            // if the user joins audio and video muted.
246
+            if (track.muted
247
+                && !(isIosMobileBrowser() && track.jitsiTrack && track.jitsiTrack.getType() === MEDIA_TYPE.AUDIO)) {
248
+                try {
249
+                    await dispatch(replaceLocalTrack(track.jitsiTrack, null));
250
+                } catch (error) {
251
+                    logger.error(`Failed to replace local track (${track.jitsiTrack}) with null: ${error}`);
252
+                }
253
+            }
254
+        }
255
+
256
+        // Re-fetch the local tracks after muted tracks have been removed above.
257
+        // This is needed, because the tracks are effectively disposed by the replaceLocalTrack and should not be used
258
+        // anymore.
259
+        localTracks = getLocalTracks(getState()['features/base/tracks']);
260
+
261
+        const jitsiTracks = localTracks.map(t => t.jitsiTrack);
262
+
263
+        dispatch(setPrejoinPageVisibility(PREJOIN_SCREEN_STATES.LOADING));
264
+
265
+        APP.conference.prejoinStart(jitsiTracks);
266
+    };
267
+}
268
+
269
+
270
+/**
271
+ * Action used to set the flag for joining operation in progress.
272
+ *
273
+ * @param {boolean} value - The config options that override the default ones (if any).
274
+ * @returns {Function}
275
+ */
276
+export function setJoiningInProgress(value: boolean) {
215 277
     return {
216
-        type: PREJOIN_START_CONFERENCE,
217
-        options
278
+        type: PREJOIN_JOINING_IN_PROGRESS,
279
+        value
218 280
     };
219 281
 }
220 282
 
283
+
221 284
 /**
222 285
  * Joins the conference without audio.
223 286
  *
@@ -225,16 +288,28 @@ export function joinConference(options?: Object) {
225 288
  */
226 289
 export function joinConferenceWithoutAudio() {
227 290
     return async function(dispatch: Function, getState: Function) {
228
-        const tracks = getState()['features/base/tracks'];
291
+        const state = getState();
292
+        const { joiningInProgress } = state['features/prejoin'];
293
+
294
+        if (joiningInProgress) {
295
+            return;
296
+        }
297
+
298
+        dispatch(setJoiningInProgress(true));
299
+        const tracks = state['features/base/tracks'];
229 300
         const audioTrack = getLocalAudioTrack(tracks)?.jitsiTrack;
230 301
 
231 302
         if (audioTrack) {
232
-            await dispatch(replaceLocalTrack(audioTrack, null));
303
+            try {
304
+                await dispatch(replaceLocalTrack(audioTrack, null));
305
+            } catch (error) {
306
+                logger.error(`Failed to replace local audio with null: ${error}`);
307
+            }
233 308
         }
234 309
 
235 310
         dispatch(joinConference({
236 311
             startSilent: true
237
-        }));
312
+        }, true));
238 313
     };
239 314
 }
240 315
 

+ 7
- 44
react/features/prejoin/middleware.js Vedi File

@@ -1,22 +1,18 @@
1 1
 // @flow
2 2
 
3
-import { CONFERENCE_JOINED } from '../base/conference';
4
-import { updateConfig } from '../base/config';
5
-import { isIosMobileBrowser } from '../base/environment/utils';
6
-import { MEDIA_TYPE, SET_AUDIO_MUTED, SET_VIDEO_MUTED } from '../base/media';
3
+import { CONFERENCE_FAILED, CONFERENCE_JOINED } from '../base/conference';
4
+import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from '../base/media';
7 5
 import { MiddlewareRegistry } from '../base/redux';
8 6
 import { updateSettings } from '../base/settings';
9 7
 import {
10
-    getLocalTracks,
11
-    replaceLocalTrack,
12 8
     TRACK_ADDED,
13 9
     TRACK_NO_DATA_FROM_SOURCE
14 10
 } from '../base/tracks';
15 11
 
16
-import { PREJOIN_START_CONFERENCE } from './actionTypes';
17 12
 import {
18 13
     setDeviceStatusOk,
19 14
     setDeviceStatusWarning,
15
+    setJoiningInProgress,
20 16
     setPrejoinPageVisibility
21 17
 } from './actions';
22 18
 import { PREJOIN_SCREEN_STATES } from './constants';
@@ -32,43 +28,6 @@ declare var APP: Object;
32 28
  */
33 29
 MiddlewareRegistry.register(store => next => async action => {
34 30
     switch (action.type) {
35
-    case PREJOIN_START_CONFERENCE: {
36
-        const { getState, dispatch } = store;
37
-        const state = getState();
38
-        const { userSelectedSkipPrejoin } = state['features/prejoin'];
39
-        let localTracks = getLocalTracks(state['features/base/tracks']);
40
-        const { options } = action;
41
-
42
-        options && store.dispatch(updateConfig(options));
43
-
44
-        userSelectedSkipPrejoin && dispatch(updateSettings({
45
-            userSelectedSkipPrejoin
46
-        }));
47
-
48
-        // Do not signal audio/video tracks if the user joins muted.
49
-        for (const track of localTracks) {
50
-            // Always add the audio track on mobile Safari because of a known issue where audio playout doesn't happen
51
-            // if the user joins audio and video muted.
52
-            if (track.muted
53
-                && !(isIosMobileBrowser() && track.jitsiTrack && track.jitsiTrack.getType() === MEDIA_TYPE.AUDIO)) {
54
-                await dispatch(replaceLocalTrack(track.jitsiTrack, null));
55
-            }
56
-        }
57
-
58
-        // Re-fetch the local tracks after muted tracks have been removed above.
59
-        // This is needed, because the tracks are effectively disposed by the replaceLocalTrack and should not be used
60
-        // anymore.
61
-        localTracks = getLocalTracks(getState()['features/base/tracks']);
62
-
63
-        const jitsiTracks = localTracks.map(t => t.jitsiTrack);
64
-
65
-        dispatch(setPrejoinPageVisibility(PREJOIN_SCREEN_STATES.LOADING));
66
-
67
-        APP.conference.prejoinStart(jitsiTracks);
68
-
69
-        break;
70
-    }
71
-
72 31
     case SET_AUDIO_MUTED: {
73 32
         if (isPrejoinPageVisible(store.getState())) {
74 33
             store.dispatch(updateSettings({
@@ -110,6 +69,9 @@ MiddlewareRegistry.register(store => next => async action => {
110 69
         }
111 70
         break;
112 71
     }
72
+    case CONFERENCE_FAILED:
73
+        store.dispatch(setJoiningInProgress(false));
74
+        break;
113 75
     case CONFERENCE_JOINED:
114 76
         return _conferenceJoined(store, next, action);
115 77
     }
@@ -127,6 +89,7 @@ MiddlewareRegistry.register(store => next => async action => {
127 89
  */
128 90
 function _conferenceJoined({ dispatch }, next, action) {
129 91
     dispatch(setPrejoinPageVisibility(PREJOIN_SCREEN_STATES.HIDDEN));
92
+    dispatch(setJoiningInProgress(false));
130 93
 
131 94
     return next(action);
132 95
 }

+ 6
- 1
react/features/prejoin/reducer.js Vedi File

@@ -1,6 +1,7 @@
1 1
 import { PersistenceRegistry, ReducerRegistry } from '../base/redux';
2 2
 
3 3
 import {
4
+    PREJOIN_JOINING_IN_PROGRESS,
4 5
     SET_DEVICE_STATUS,
5 6
     SET_DIALOUT_COUNTRY,
6 7
     SET_DIALOUT_NUMBER,
@@ -53,7 +54,11 @@ PersistenceRegistry.register(STORE_NAME, {
53 54
 ReducerRegistry.register(
54 55
     'features/prejoin', (state = DEFAULT_STATE, action) => {
55 56
         switch (action.type) {
56
-
57
+        case PREJOIN_JOINING_IN_PROGRESS:
58
+            return {
59
+                ...state,
60
+                joiningInProgress: action.value
61
+            };
57 62
         case SET_SKIP_PREJOIN: {
58 63
             return {
59 64
                 ...state,

Loading…
Annulla
Salva