Procházet zdrojové kódy

fix(prejoin): Store prejoin tracks in 'features/base/tracks'

master
Vlad Piersec před 4 roky
rodič
revize
4f169988a3

+ 1
- 28
conference.js Zobrazit soubor

@@ -118,10 +118,7 @@ import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay
118 118
 import { suspendDetected } from './react/features/power-monitor';
119 119
 import {
120 120
     initPrejoin,
121
-    isPrejoinPageEnabled,
122
-    isPrejoinPageVisible,
123
-    replacePrejoinAudioTrack,
124
-    replacePrejoinVideoTrack
121
+    isPrejoinPageEnabled
125 122
 } from './react/features/prejoin';
126 123
 import { createRnnoiseProcessorPromise } from './react/features/rnnoise';
127 124
 import { toggleScreenshotCaptureEffect } from './react/features/screenshot-capture';
@@ -1409,18 +1406,6 @@ export default {
1409 1406
     useVideoStream(newStream) {
1410 1407
         return new Promise((resolve, reject) => {
1411 1408
             _replaceLocalVideoTrackQueue.enqueue(onFinish => {
1412
-                /**
1413
-                 * When the prejoin page is visible there is no conference object
1414
-                 * created. The prejoin tracks are managed separately,
1415
-                 * so this updates the prejoin video track.
1416
-                 */
1417
-                if (isPrejoinPageVisible(APP.store.getState())) {
1418
-                    return APP.store.dispatch(replacePrejoinVideoTrack(newStream))
1419
-                        .then(resolve)
1420
-                        .catch(reject)
1421
-                        .then(onFinish);
1422
-                }
1423
-
1424 1409
                 APP.store.dispatch(
1425 1410
                 replaceLocalTrack(this.localVideo, newStream, room))
1426 1411
                     .then(() => {
@@ -1474,18 +1459,6 @@ export default {
1474 1459
     useAudioStream(newStream) {
1475 1460
         return new Promise((resolve, reject) => {
1476 1461
             _replaceLocalAudioTrackQueue.enqueue(onFinish => {
1477
-                /**
1478
-                 * When the prejoin page is visible there is no conference object
1479
-                 * created. The prejoin tracks are managed separately,
1480
-                 * so this updates the prejoin audio stream.
1481
-                 */
1482
-                if (isPrejoinPageVisible(APP.store.getState())) {
1483
-                    return APP.store.dispatch(replacePrejoinAudioTrack(newStream))
1484
-                        .then(resolve)
1485
-                        .catch(reject)
1486
-                        .then(onFinish);
1487
-                }
1488
-
1489 1462
                 APP.store.dispatch(
1490 1463
                 replaceLocalTrack(this.localAudio, newStream, room))
1491 1464
                     .then(() => {

+ 4
- 0
css/_settings-button.scss Zobrazit soubor

@@ -35,6 +35,10 @@
35 35
                 cursor: initial;
36 36
                 color: #fff;
37 37
                 background-color: #a4b8d1;
38
+
39
+                &:hover {
40
+                    background-color: #a4b8d1;
41
+                }
38 42
             }
39 43
 
40 44
             svg {

+ 11
- 0
react/features/base/media/functions.js Zobrazit soubor

@@ -4,6 +4,17 @@ import { toState } from '../redux';
4 4
 
5 5
 import { VIDEO_MUTISM_AUTHORITY } from './constants';
6 6
 
7
+/**
8
+ * Determines whether audio is currently muted.
9
+ *
10
+ * @param {Function|Object} stateful - The redux store, state, or
11
+ * {@code getState} function.
12
+ * @returns {boolean}
13
+ */
14
+export function isAudioMuted(stateful: Function | Object) {
15
+    return Boolean(toState(stateful)['features/base/media'].audio.muted);
16
+}
17
+
7 18
 /**
8 19
  * Determines whether video is currently muted by the audio-only authority.
9 20
  *

+ 18
- 2
react/features/base/settings/functions.web.js Zobrazit soubor

@@ -9,7 +9,7 @@ export * from './functions.any';
9 9
  * @returns {void}
10 10
  */
11 11
 export function getCurrentCameraDeviceId(state: Object) {
12
-    return state['features/base/settings'].cameraDeviceId;
12
+    return getDeviceIdByType(state, 'isVideoTrack');
13 13
 }
14 14
 
15 15
 /**
@@ -19,7 +19,7 @@ export function getCurrentCameraDeviceId(state: Object) {
19 19
  * @returns {void}
20 20
  */
21 21
 export function getCurrentMicDeviceId(state: Object) {
22
-    return state['features/base/settings'].micDeviceId;
22
+    return getDeviceIdByType(state, 'isAudioTrack');
23 23
 }
24 24
 
25 25
 /**
@@ -32,6 +32,22 @@ export function getCurrentOutputDeviceId(state: Object) {
32 32
     return state['features/base/settings'].audioOutputDeviceId;
33 33
 }
34 34
 
35
+/**
36
+ * Returns the deviceId for the corresponding local track type.
37
+ *
38
+ * @param {Object} state - The state of the application.
39
+ * @param {string} isType - Can be 'isVideoTrack' | 'isAudioTrack'.
40
+ * @returns {string}
41
+ */
42
+function getDeviceIdByType(state: Object, isType: string) {
43
+    const [ deviceId ] = state['features/base/tracks']
44
+          .map(t => t.jitsiTrack)
45
+          .filter(t => t && t.isLocal() && t[isType]())
46
+          .map(t => t.getDeviceId());
47
+
48
+    return deviceId || '';
49
+}
50
+
35 51
 /**
36 52
  * Returns the saved display name.
37 53
  *

+ 58
- 44
react/features/base/tracks/actions.js Zobrazit soubor

@@ -267,56 +267,70 @@ export function toggleScreensharing() {
267 267
  * @returns {Function}
268 268
  */
269 269
 export function replaceLocalTrack(oldTrack, newTrack, conference) {
270
-    return (dispatch, getState) => {
270
+    return async (dispatch, getState) => {
271 271
         conference
272 272
 
273 273
             // eslint-disable-next-line no-param-reassign
274 274
             || (conference = getState()['features/base/conference'].conference);
275 275
 
276
-        return conference.replaceTrack(oldTrack, newTrack)
276
+        if (conference) {
277
+            await conference.replaceTrack(oldTrack, newTrack);
278
+        }
279
+
280
+        return dispatch(replaceStoredTracks(oldTrack, newTrack));
281
+    };
282
+}
283
+
284
+/**
285
+ * Replaces a stored track with another.
286
+ *
287
+ * @param {JitsiLocalTrack|null} oldTrack - The track to dispose.
288
+ * @param {JitsiLocalTrack|null} newTrack - The track to use instead.
289
+ * @returns {Function}
290
+ */
291
+function replaceStoredTracks(oldTrack, newTrack) {
292
+    return dispatch => {
293
+        // We call dispose after doing the replace because dispose will
294
+        // try and do a new o/a after the track removes itself. Doing it
295
+        // after means the JitsiLocalTrack.conference is already
296
+        // cleared, so it won't try and do the o/a.
297
+        const disposePromise
298
+              = oldTrack
299
+                  ? dispatch(_disposeAndRemoveTracks([ oldTrack ]))
300
+                  : Promise.resolve();
301
+
302
+        return disposePromise
277 303
             .then(() => {
278
-                // We call dispose after doing the replace because dispose will
279
-                // try and do a new o/a after the track removes itself. Doing it
280
-                // after means the JitsiLocalTrack.conference is already
281
-                // cleared, so it won't try and do the o/a.
282
-                const disposePromise
283
-                    = oldTrack
284
-                        ? dispatch(_disposeAndRemoveTracks([ oldTrack ]))
285
-                        : Promise.resolve();
286
-
287
-                return disposePromise
288
-                    .then(() => {
289
-                        if (newTrack) {
290
-                            // The mute state of the new track should be
291
-                            // reflected in the app's mute state. For example,
292
-                            // if the app is currently muted and changing to a
293
-                            // new track that is not muted, the app's mute
294
-                            // state should be falsey. As such, emit a mute
295
-                            // event here to set up the app to reflect the
296
-                            // track's mute state. If this is not done, the
297
-                            // current mute state of the app will be reflected
298
-                            // on the track, not vice-versa.
299
-                            const setMuted
300
-                                = newTrack.isVideoTrack()
301
-                                    ? setVideoMuted
302
-                                    : setAudioMuted;
303
-                            const isMuted = newTrack.isMuted();
304
-
305
-                            sendAnalytics(createTrackMutedEvent(
306
-                                newTrack.getType(),
307
-                                'track.replaced',
308
-                                isMuted));
309
-                            logger.log(`Replace ${newTrack.getType()} track - ${
310
-                                isMuted ? 'muted' : 'unmuted'}`);
311
-
312
-                            return dispatch(setMuted(isMuted));
313
-                        }
314
-                    })
315
-                    .then(() => {
316
-                        if (newTrack) {
317
-                            return dispatch(_addTracks([ newTrack ]));
318
-                        }
319
-                    });
304
+                if (newTrack) {
305
+                    // The mute state of the new track should be
306
+                    // reflected in the app's mute state. For example,
307
+                    // if the app is currently muted and changing to a
308
+                    // new track that is not muted, the app's mute
309
+                    // state should be falsey. As such, emit a mute
310
+                    // event here to set up the app to reflect the
311
+                    // track's mute state. If this is not done, the
312
+                    // current mute state of the app will be reflected
313
+                    // on the track, not vice-versa.
314
+                    const setMuted
315
+                          = newTrack.isVideoTrack()
316
+                              ? setVideoMuted
317
+                              : setAudioMuted;
318
+                    const isMuted = newTrack.isMuted();
319
+
320
+                    sendAnalytics(createTrackMutedEvent(
321
+                        newTrack.getType(),
322
+                        'track.replaced',
323
+                        isMuted));
324
+                    logger.log(`Replace ${newTrack.getType()} track - ${
325
+                        isMuted ? 'muted' : 'unmuted'}`);
326
+
327
+                    return dispatch(setMuted(isMuted));
328
+                }
329
+            })
330
+            .then(() => {
331
+                if (newTrack) {
332
+                    return dispatch(_addTracks([ newTrack ]));
333
+                }
320 334
             });
321 335
     };
322 336
 }

+ 12
- 0
react/features/base/tracks/functions.js Zobrazit soubor

@@ -200,6 +200,18 @@ export function getLocalVideoType(tracks) {
200 200
     return presenterTrack ? MEDIA_TYPE.PRESENTER : MEDIA_TYPE.VIDEO;
201 201
 }
202 202
 
203
+/**
204
+ * Returns the stored local video track.
205
+ *
206
+ * @param {Object} state - The redux state.
207
+ * @returns {Object}
208
+ */
209
+export function getLocalJitsiVideoTrack(state) {
210
+    const track = getLocalVideoTrack(state['features/base/tracks']);
211
+
212
+    return track?.jitsiTrack;
213
+}
214
+
203 215
 /**
204 216
  * Returns track of specified media type for specified participant id.
205 217
  *

+ 13
- 1
react/features/base/tracks/middleware.js Zobrazit soubor

@@ -2,6 +2,8 @@
2 2
 
3 3
 import UIEvents from '../../../../service/UI/UIEvents';
4 4
 import { hideNotification } from '../../notifications';
5
+import { isPrejoinPageVisible } from '../../prejoin/functions';
6
+import { getAvailableDevices } from '../devices/actions';
5 7
 import {
6 8
     CAMERA_FACING_MODE,
7 9
     MEDIA_TYPE,
@@ -15,6 +17,7 @@ import {
15 17
 import { MiddlewareRegistry } from '../redux';
16 18
 
17 19
 import {
20
+    TRACK_ADDED,
18 21
     TOGGLE_SCREENSHARING,
19 22
     TRACK_NO_DATA_FROM_SOURCE,
20 23
     TRACK_REMOVED,
@@ -44,6 +47,15 @@ declare var APP: Object;
44 47
  */
45 48
 MiddlewareRegistry.register(store => next => action => {
46 49
     switch (action.type) {
50
+    case TRACK_ADDED: {
51
+        // The devices list needs to be refreshed when no initial video permissions
52
+        // were granted and a local video track is added by umuting the video.
53
+        if (action.track.local) {
54
+            store.dispatch(getAvailableDevices());
55
+        }
56
+
57
+        break;
58
+    }
47 59
     case TRACK_NO_DATA_FROM_SOURCE: {
48 60
         const result = next(action);
49 61
 
@@ -281,7 +293,7 @@ function _setMuted(store, { ensureTrack, authority, muted }, mediaType: MEDIA_TY
281 293
         // anymore, unless it is muted by audioOnly.
282 294
         jitsiTrack && (jitsiTrack.videoType !== 'desktop' || isAudioOnly)
283 295
             && setTrackMuted(jitsiTrack, muted);
284
-    } else if (!muted && ensureTrack && typeof APP === 'undefined') {
296
+    } else if (!muted && ensureTrack && (typeof APP === 'undefined' || isPrejoinPageVisible(store.getState()))) {
285 297
         // FIXME: This only runs on mobile now because web has its own way of
286 298
         // creating local tracks. Adjust the check once they are unified.
287 299
         store.dispatch(createLocalTracksA({ devices: [ mediaType ] }));

+ 0
- 25
react/features/prejoin/actionTypes.js Zobrazit soubor

@@ -1,18 +1,3 @@
1
-/**
2
- * Action type to add a video track to the store.
3
- */
4
-export const ADD_PREJOIN_VIDEO_TRACK = 'ADD_PREJOIN_VIDEO_TRACK';
5
-
6
-/**
7
- * Action type to add an audio track to the store.
8
- */
9
-export const ADD_PREJOIN_AUDIO_TRACK = 'ADD_PREJOIN_AUDIO_TRACK';
10
-
11
-/**
12
- * Action type to add a content sharing track to the store.
13
- */
14
-export const ADD_PREJOIN_CONTENT_SHARING_TRACK
15
-    = 'ADD_PREJOIN_CONTENT_SHARING_TRACK';
16 1
 
17 2
 /**
18 3
  * Action type to signal the start of the conference.
@@ -68,13 +53,3 @@ export const SET_PREJOIN_DEVICE_ERRORS = 'SET_PREJOIN_DEVICE_ERRORS';
68 53
  * Action type to set the visibility of the prejoin page.
69 54
  */
70 55
 export const SET_PREJOIN_PAGE_VISIBILITY = 'SET_PREJOIN_PAGE_VISIBILITY';
71
-
72
-/**
73
- * Action type to mute/unmute the video while on prejoin page.
74
- */
75
-export const SET_PREJOIN_VIDEO_DISABLED = 'SET_PREJOIN_VIDEO_DISABLED';
76
-
77
-/**
78
- * Action type to mute/unmute the video while on prejoin page.
79
- */
80
-export const SET_PREJOIN_VIDEO_MUTED = 'SET_PREJOIN_VIDEO_MUTED';

+ 21
- 158
react/features/prejoin/actions.js Zobrazit soubor

@@ -5,14 +5,17 @@ import uuid from 'uuid';
5 5
 import { getRoomName } from '../base/conference';
6 6
 import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions';
7 7
 import { createLocalTrack } from '../base/lib-jitsi-meet';
8
+import {
9
+    getLocalAudioTrack,
10
+    getLocalVideoTrack,
11
+    trackAdded,
12
+    replaceLocalTrack
13
+} from '../base/tracks';
8 14
 import { openURLInBrowser } from '../base/util';
9 15
 import { executeDialOutRequest, executeDialOutStatusRequest, getDialInfoPageURL } from '../invite/functions';
10 16
 import { showErrorNotification } from '../notifications';
11 17
 
12 18
 import {
13
-    ADD_PREJOIN_AUDIO_TRACK,
14
-    ADD_PREJOIN_CONTENT_SHARING_TRACK,
15
-    ADD_PREJOIN_VIDEO_TRACK,
16 19
     PREJOIN_START_CONFERENCE,
17 20
     SET_DEVICE_STATUS,
18 21
     SET_DIALOUT_COUNTRY,
@@ -20,19 +23,13 @@ import {
20 23
     SET_DIALOUT_STATUS,
21 24
     SET_SKIP_PREJOIN,
22 25
     SET_JOIN_BY_PHONE_DIALOG_VISIBLITY,
23
-    SET_PREJOIN_AUDIO_DISABLED,
24
-    SET_PREJOIN_AUDIO_MUTED,
25 26
     SET_PREJOIN_DEVICE_ERRORS,
26
-    SET_PREJOIN_PAGE_VISIBILITY,
27
-    SET_PREJOIN_VIDEO_DISABLED,
28
-    SET_PREJOIN_VIDEO_MUTED
27
+    SET_PREJOIN_PAGE_VISIBILITY
29 28
 } from './actionTypes';
30 29
 import {
31 30
     getFullDialOutNumber,
32
-    getAudioTrack,
33 31
     getDialOutConferenceUrl,
34 32
     getDialOutCountry,
35
-    getVideoTrack,
36 33
     isJoinByPhoneDialogVisible
37 34
 } from './functions';
38 35
 import logger from './logger';
@@ -60,45 +57,6 @@ const STATUS_REQ_FREQUENCY = 2000;
60 57
  */
61 58
 const STATUS_REQ_CAP = 45;
62 59
 
63
-/**
64
- * Action used to add an audio track to the store.
65
- *
66
- * @param {Object} value - The track to be added.
67
- * @returns {Object}
68
- */
69
-export function addPrejoinAudioTrack(value: Object) {
70
-    return {
71
-        type: ADD_PREJOIN_AUDIO_TRACK,
72
-        value
73
-    };
74
-}
75
-
76
-/**
77
- * Action used to add a video track to the store.
78
- *
79
- * @param {Object} value - The track to be added.
80
- * @returns {Object}
81
- */
82
-export function addPrejoinVideoTrack(value: Object) {
83
-    return {
84
-        type: ADD_PREJOIN_VIDEO_TRACK,
85
-        value
86
-    };
87
-}
88
-
89
-/**
90
- * Action used to add a content sharing track to the store.
91
- *
92
- * @param {Object} value - The track to be added.
93
- * @returns {Object}
94
- */
95
-export function addPrejoinContentSharingTrack(value: Object) {
96
-    return {
97
-        type: ADD_PREJOIN_CONTENT_SHARING_TRACK,
98
-        value
99
-    };
100
-}
101
-
102 60
 /**
103 61
  * Polls for status change after dial out.
104 62
  * Changes dialog message based on response, closes the dialog if there is an error,
@@ -232,27 +190,10 @@ export function dialOut(onSuccess: Function, onFail: Function) {
232 190
  */
233 191
 export function initPrejoin(tracks: Object[], errors: Object) {
234 192
     return async function(dispatch: Function) {
235
-        const audioTrack = tracks.find(t => t.isAudioTrack());
236
-        const videoTrack = tracks.find(t => t.isVideoTrack());
237
-
238 193
         dispatch(setPrejoinDeviceErrors(errors));
239 194
 
240
-        if (audioTrack) {
241
-            dispatch(addPrejoinAudioTrack(audioTrack));
242
-        } else {
243
-            dispatch(setAudioDisabled());
244
-        }
245 195
 
246
-        if (videoTrack) {
247
-            if (videoTrack.videoType === 'desktop') {
248
-                dispatch(addPrejoinContentSharingTrack(videoTrack));
249
-                dispatch(setPrejoinVideoDisabled(true));
250
-            } else {
251
-                dispatch(addPrejoinVideoTrack(videoTrack));
252
-            }
253
-        } else {
254
-            dispatch(setPrejoinVideoDisabled(true));
255
-        }
196
+        tracks.forEach(track => dispatch(trackAdded(track)));
256 197
     };
257 198
 }
258 199
 
@@ -275,12 +216,12 @@ export function joinConference() {
275 216
  */
276 217
 export function joinConferenceWithoutAudio() {
277 218
     return async function(dispatch: Function, getState: Function) {
278
-        const audioTrack = getAudioTrack(getState());
219
+        const tracks = getState()['features/base/tracks'];
220
+        const audioTrack = getLocalAudioTrack(tracks)?.jitsiTrack;
279 221
 
280 222
         if (audioTrack) {
281
-            await dispatch(replacePrejoinAudioTrack(null));
223
+            await dispatch(replaceLocalTrack(audioTrack, null));
282 224
         }
283
-        dispatch(setAudioDisabled());
284 225
         dispatch(joinConference());
285 226
     };
286 227
 }
@@ -301,21 +242,6 @@ export function openDialInPage() {
301 242
     };
302 243
 }
303 244
 
304
-/**
305
- * Replaces the existing audio track with a new one.
306
- *
307
- * @param {Object} track - The new track.
308
- * @returns {Function}
309
- */
310
-export function replacePrejoinAudioTrack(track: Object) {
311
-    return async (dispatch: Function, getState: Function) => {
312
-        const oldTrack = getAudioTrack(getState());
313
-
314
-        oldTrack && await oldTrack.dispose();
315
-        dispatch(addPrejoinAudioTrack(track));
316
-    };
317
-}
318
-
319 245
 /**
320 246
  * Creates a new audio track based on a device id and replaces the current one.
321 247
  *
@@ -323,11 +249,13 @@ export function replacePrejoinAudioTrack(track: Object) {
323 249
  * @returns {Function}
324 250
  */
325 251
 export function replaceAudioTrackById(deviceId: string) {
326
-    return async (dispatch: Function) => {
252
+    return async (dispatch: Function, getState: Function) => {
327 253
         try {
328
-            const track = await createLocalTrack('audio', deviceId);
254
+            const tracks = getState()['features/base/tracks'];
255
+            const newTrack = await createLocalTrack('audio', deviceId);
256
+            const oldTrack = getLocalAudioTrack(tracks)?.jitsiTrack;
329 257
 
330
-            dispatch(replacePrejoinAudioTrack(track));
258
+            dispatch(replaceLocalTrack(oldTrack, newTrack));
331 259
         } catch (err) {
332 260
             dispatch(setDeviceStatusWarning('prejoin.audioTrackError'));
333 261
             logger.log('Error replacing audio track', err);
@@ -335,21 +263,6 @@ export function replaceAudioTrackById(deviceId: string) {
335 263
     };
336 264
 }
337 265
 
338
-/**
339
- * Replaces the existing video track with a new one.
340
- *
341
- * @param {Object} track - The new track.
342
- * @returns {Function}
343
- */
344
-export function replacePrejoinVideoTrack(track: Object) {
345
-    return async (dispatch: Function, getState: Function) => {
346
-        const oldTrack = getVideoTrack(getState());
347
-
348
-        oldTrack && await oldTrack.dispose();
349
-        dispatch(addPrejoinVideoTrack(track));
350
-    };
351
-}
352
-
353 266
 /**
354 267
  * Creates a new video track based on a device id and replaces the current one.
355 268
  *
@@ -357,11 +270,13 @@ export function replacePrejoinVideoTrack(track: Object) {
357 270
  * @returns {Function}
358 271
  */
359 272
 export function replaceVideoTrackById(deviceId: Object) {
360
-    return async (dispatch: Function) => {
273
+    return async (dispatch: Function, getState: Function) => {
361 274
         try {
362
-            const track = await createLocalTrack('video', deviceId);
275
+            const tracks = getState()['features/base/tracks'];
276
+            const newTrack = await createLocalTrack('video', deviceId);
277
+            const oldTrack = getLocalVideoTrack(tracks)?.jitsiTrack;
363 278
 
364
-            dispatch(replacePrejoinVideoTrack(track));
279
+            dispatch(replaceLocalTrack(oldTrack, newTrack));
365 280
         } catch (err) {
366 281
             dispatch(setDeviceStatusWarning('prejoin.videoTrackError'));
367 282
             logger.log('Error replacing video track', err);
@@ -369,58 +284,6 @@ export function replaceVideoTrackById(deviceId: Object) {
369 284
     };
370 285
 }
371 286
 
372
-
373
-/**
374
- * Action used to mark audio muted.
375
- *
376
- * @param {boolean} value - True for muted.
377
- * @returns {Object}
378
- */
379
-export function setPrejoinAudioMuted(value: boolean) {
380
-    return {
381
-        type: SET_PREJOIN_AUDIO_MUTED,
382
-        value
383
-    };
384
-}
385
-
386
-/**
387
- * Action used to mark video disabled.
388
- *
389
- * @param {boolean} value - True for muted.
390
- * @returns {Object}
391
- */
392
-export function setPrejoinVideoDisabled(value: boolean) {
393
-    return {
394
-        type: SET_PREJOIN_VIDEO_DISABLED,
395
-        value
396
-    };
397
-}
398
-
399
-
400
-/**
401
- * Action used to mark video muted.
402
- *
403
- * @param {boolean} value - True for muted.
404
- * @returns {Object}
405
- */
406
-export function setPrejoinVideoMuted(value: boolean) {
407
-    return {
408
-        type: SET_PREJOIN_VIDEO_MUTED,
409
-        value
410
-    };
411
-}
412
-
413
-/**
414
- * Action used to mark audio as disabled.
415
- *
416
- * @returns {Object}
417
- */
418
-export function setAudioDisabled() {
419
-    return {
420
-        type: SET_PREJOIN_AUDIO_DISABLED
421
-    };
422
-}
423
-
424 287
 /**
425 288
  * Sets the device status as OK with the corresponding text.
426 289
  *

+ 5
- 5
react/features/prejoin/components/Prejoin.js Zobrazit soubor

@@ -6,9 +6,11 @@ import React, { Component } from 'react';
6 6
 import { getRoomName } from '../../base/conference';
7 7
 import { translate } from '../../base/i18n';
8 8
 import { Icon, IconPhone, IconVolumeOff } from '../../base/icons';
9
+import { isVideoMutedByUser } from '../../base/media';
9 10
 import { ActionButton, InputField, PreMeetingScreen } from '../../base/premeeting';
10 11
 import { connect } from '../../base/redux';
11 12
 import { getDisplayName, updateSettings } from '../../base/settings';
13
+import { getLocalJitsiVideoTrack } from '../../base/tracks';
12 14
 import {
13 15
     joinConference as joinConferenceAction,
14 16
     joinConferenceWithoutAudio as joinConferenceWithoutAudioAction,
@@ -16,11 +18,9 @@ import {
16 18
     setJoinByPhoneDialogVisiblity as setJoinByPhoneDialogVisiblityAction
17 19
 } from '../actions';
18 20
 import {
19
-    getActiveVideoTrack,
20 21
     isJoinByPhoneButtonVisible,
21 22
     isDeviceStatusVisible,
22
-    isJoinByPhoneDialogVisible,
23
-    isPrejoinVideoMuted
23
+    isJoinByPhoneDialogVisible
24 24
 } from '../functions';
25 25
 
26 26
 import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
@@ -315,8 +315,8 @@ function mapStateToProps(state): Object {
315 315
         roomName: getRoomName(state),
316 316
         showDialog: isJoinByPhoneDialogVisible(state),
317 317
         hasJoinByPhoneButton: isJoinByPhoneButtonVisible(state),
318
-        showCameraPreview: !isPrejoinVideoMuted(state),
319
-        videoTrack: getActiveVideoTrack(state)
318
+        showCameraPreview: !isVideoMutedByUser(state),
319
+        videoTrack: getLocalJitsiVideoTrack(state)
320 320
     };
321 321
 }
322 322
 

+ 3
- 136
react/features/prejoin/functions.js Zobrazit soubor

@@ -2,25 +2,7 @@
2 2
 
3 3
 import { getRoomName } from '../base/conference';
4 4
 import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions';
5
-
6
-/**
7
- * Mutes or unmutes a track.
8
- *
9
- * @param {Object} track - The track to be configured.
10
- * @param {boolean} shouldMute - If it should mute or not.
11
- * @returns {Promise<void>}
12
- */
13
-function applyMuteOptionsToTrack(track, shouldMute) {
14
-    if (track.isMuted() === shouldMute) {
15
-        return;
16
-    }
17
-
18
-    if (shouldMute) {
19
-        return track.mute();
20
-    }
21
-
22
-    return track.unmute();
23
-}
5
+import { isAudioMuted, isVideoMutedByUser } from '../base/media';
24 6
 
25 7
 /**
26 8
  * Selector for the visibility of the 'join by phone' button.
@@ -39,73 +21,8 @@ export function isJoinByPhoneButtonVisible(state: Object): boolean {
39 21
  * @returns {boolean}
40 22
  */
41 23
 export function isDeviceStatusVisible(state: Object): boolean {
42
-    return !((isAudioDisabled(state) && isPrejoinVideoDisabled(state))
43
-        || (isPrejoinAudioMuted(state) && isPrejoinVideoMuted(state)));
44
-}
45
-
46
-/**
47
- * Selector for getting the active video/content sharing track.
48
- *
49
- * @param {Object} state - The state of the app.
50
- * @returns {boolean}
51
- */
52
-export function getActiveVideoTrack(state: Object): Object {
53
-    const track = getVideoTrack(state) || getContentSharingTrack(state);
54
-
55
-    if (track && track.isActive()) {
56
-        return track;
57
-    }
58
-
59
-    return null;
60
-}
61
-
62
-/**
63
- * Returns a list with all the prejoin tracks configured according to
64
- * user's preferences.
65
- *
66
- * @param {Object} state - The state of the app.
67
- * @returns {Promise<Object[]>}
68
- */
69
-export async function getAllPrejoinConfiguredTracks(state: Object): Promise<Object[]> {
70
-    const tracks = [];
71
-    const audioTrack = getAudioTrack(state);
72
-    const videoTrack = getVideoTrack(state);
73
-    const csTrack = getContentSharingTrack(state);
74
-
75
-    if (csTrack) {
76
-        tracks.push(csTrack);
77
-    } else if (videoTrack) {
78
-        await applyMuteOptionsToTrack(videoTrack, isPrejoinVideoMuted(state));
79
-        tracks.push(videoTrack);
80
-    }
81
-
82
-    if (audioTrack) {
83
-        await applyMuteOptionsToTrack(audioTrack, isPrejoinAudioMuted(state));
84
-        isPrejoinAudioMuted(state) && audioTrack.mute();
85
-        tracks.push(audioTrack);
86
-    }
87
-
88
-    return tracks;
89
-}
90
-
91
-/**
92
- * Selector for getting the prejoin audio track.
93
- *
94
- * @param {Object} state - The state of the app.
95
- * @returns {Object}
96
- */
97
-export function getAudioTrack(state: Object): Object {
98
-    return state['features/prejoin']?.audioTrack;
99
-}
100
-
101
-/**
102
- * Selector for getting the prejoin content sharing track.
103
- *
104
- * @param {Object} state - The state of the app.
105
- * @returns {Object}
106
- */
107
-export function getContentSharingTrack(state: Object): Object {
108
-    return state['features/prejoin']?.contentSharingTrack;
24
+    return !(isAudioMuted(state) && isVideoMutedByUser(state))
25
+    && !state['features/base/config'].startSilent;
109 26
 }
110 27
 
111 28
 /**
@@ -181,36 +98,6 @@ export function getFullDialOutNumber(state: Object): string {
181 98
     return `+${country.dialCode}${dialOutNumber}`;
182 99
 }
183 100
 
184
-/**
185
- * Selector for getting the prejoin video track.
186
- *
187
- * @param {Object} state - The state of the app.
188
- * @returns {Object}
189
- */
190
-export function getVideoTrack(state: Object): Object {
191
-    return state['features/prejoin']?.videoTrack;
192
-}
193
-
194
-/**
195
- * Selector for getting the mute status of the prejoin audio.
196
- *
197
- * @param {Object} state - The state of the app.
198
- * @returns {boolean}
199
- */
200
-export function isPrejoinAudioMuted(state: Object): boolean {
201
-    return state['features/prejoin']?.audioMuted;
202
-}
203
-
204
-/**
205
- * Selector for getting the mute status of the prejoin video.
206
- *
207
- * @param {Object} state - The state of the app.
208
- * @returns {boolean}
209
- */
210
-export function isPrejoinVideoMuted(state: Object): boolean {
211
-    return state['features/prejoin']?.videoMuted;
212
-}
213
-
214 101
 /**
215 102
  * Selector for getting the error if any while creating streams.
216 103
  *
@@ -221,26 +108,6 @@ export function getRawError(state: Object): string {
221 108
     return state['features/prejoin']?.rawError;
222 109
 }
223 110
 
224
-/**
225
- * Selector for getting state of the prejoin audio.
226
- *
227
- * @param {Object} state - The state of the app.
228
- * @returns {boolean}
229
- */
230
-export function isAudioDisabled(state: Object): Object {
231
-    return state['features/prejoin']?.audioDisabled;
232
-}
233
-
234
-/**
235
- * Selector for getting state of the prejoin video.
236
- *
237
- * @param {Object} state - The state of the app.
238
- * @returns {boolean}
239
- */
240
-export function isPrejoinVideoDisabled(state: Object): Object {
241
-    return state['features/prejoin']?.videoDisabled;
242
-}
243
-
244 111
 /**
245 112
  * Selector for getting the visiblity state for the 'JoinByPhoneDialog'.
246 113
  *

+ 3
- 50
react/features/prejoin/middleware.js Zobrazit soubor

@@ -1,16 +1,9 @@
1 1
 // @flow
2 2
 
3
-import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from '../base/media';
4 3
 import { MiddlewareRegistry } from '../base/redux';
5 4
 import { updateSettings } from '../base/settings';
6 5
 
7
-import {
8
-    ADD_PREJOIN_AUDIO_TRACK,
9
-    ADD_PREJOIN_VIDEO_TRACK,
10
-    PREJOIN_START_CONFERENCE
11
-} from './actionTypes';
12
-import { setPrejoinAudioMuted, setPrejoinVideoMuted } from './actions';
13
-import { getAllPrejoinConfiguredTracks } from './functions';
6
+import { PREJOIN_START_CONFERENCE } from './actionTypes';
14 7
 
15 8
 declare var APP: Object;
16 9
 
@@ -22,62 +15,22 @@ declare var APP: Object;
22 15
  */
23 16
 MiddlewareRegistry.register(store => next => async action => {
24 17
     switch (action.type) {
25
-    case ADD_PREJOIN_AUDIO_TRACK: {
26
-        const { value: audioTrack } = action;
27
-
28
-        if (audioTrack) {
29
-            store.dispatch(
30
-                    updateSettings({
31
-                        micDeviceId: audioTrack.getDeviceId()
32
-                    }),
33
-            );
34
-        }
35
-
36
-        break;
37
-    }
38
-
39
-    case ADD_PREJOIN_VIDEO_TRACK: {
40
-        const { value: videoTrack } = action;
41
-
42
-        if (videoTrack) {
43
-            store.dispatch(
44
-                    updateSettings({
45
-                        cameraDeviceId: videoTrack.getDeviceId()
46
-                    }),
47
-            );
48
-        }
49
-
50
-        break;
51
-    }
52
-
53 18
     case PREJOIN_START_CONFERENCE: {
54 19
         const { getState, dispatch } = store;
55 20
         const state = getState();
56 21
         const { userSelectedSkipPrejoin } = state['features/prejoin'];
22
+        const tracks = state['features/base/tracks'];
57 23
 
58 24
         userSelectedSkipPrejoin && dispatch(updateSettings({
59 25
             userSelectedSkipPrejoin
60 26
         }));
61 27
 
62
-
63
-        const tracks = await getAllPrejoinConfiguredTracks(state);
64
-
65
-        APP.conference.prejoinStart(tracks);
28
+        APP.conference.prejoinStart(tracks.map(t => t.jitsiTrack));
66 29
 
67 30
         break;
68 31
     }
69
-
70
-    case SET_AUDIO_MUTED: {
71
-        store.dispatch(setPrejoinAudioMuted(Boolean(action.muted)));
72
-        break;
73 32
     }
74 33
 
75
-    case SET_VIDEO_MUTED: {
76
-        store.dispatch(setPrejoinVideoMuted(Boolean(action.muted)));
77
-        break;
78
-    }
79
-
80
-    }
81 34
 
82 35
     return next(action);
83 36
 });

+ 2
- 62
react/features/prejoin/reducer.js Zobrazit soubor

@@ -1,28 +1,17 @@
1 1
 import { ReducerRegistry } from '../base/redux';
2 2
 
3 3
 import {
4
-    ADD_PREJOIN_AUDIO_TRACK,
5
-    ADD_PREJOIN_CONTENT_SHARING_TRACK,
6
-    ADD_PREJOIN_VIDEO_TRACK,
7 4
     SET_DEVICE_STATUS,
8 5
     SET_DIALOUT_NUMBER,
9 6
     SET_DIALOUT_COUNTRY,
10 7
     SET_DIALOUT_STATUS,
11 8
     SET_JOIN_BY_PHONE_DIALOG_VISIBLITY,
12 9
     SET_SKIP_PREJOIN,
13
-    SET_PREJOIN_AUDIO_DISABLED,
14
-    SET_PREJOIN_AUDIO_MUTED,
15 10
     SET_PREJOIN_DEVICE_ERRORS,
16
-    SET_PREJOIN_PAGE_VISIBILITY,
17
-    SET_PREJOIN_VIDEO_DISABLED,
18
-    SET_PREJOIN_VIDEO_MUTED
11
+    SET_PREJOIN_PAGE_VISIBILITY
19 12
 } from './actionTypes';
20 13
 
21 14
 const DEFAULT_STATE = {
22
-    audioDisabled: false,
23
-    audioMuted: false,
24
-    audioTrack: null,
25
-    contentSharingTrack: null,
26 15
     country: '',
27 16
     deviceStatusText: 'prejoin.configuringDevices',
28 17
     deviceStatusType: 'ok',
@@ -37,10 +26,7 @@ const DEFAULT_STATE = {
37 26
     rawError: '',
38 27
     showPrejoin: true,
39 28
     showJoinByPhoneDialog: false,
40
-    userSelectedSkipPrejoin: false,
41
-    videoTrack: null,
42
-    videoDisabled: false,
43
-    videoMuted: false
29
+    userSelectedSkipPrejoin: false
44 30
 };
45 31
 
46 32
 /**
@@ -49,26 +35,6 @@ const DEFAULT_STATE = {
49 35
 ReducerRegistry.register(
50 36
     'features/prejoin', (state = DEFAULT_STATE, action) => {
51 37
         switch (action.type) {
52
-        case ADD_PREJOIN_AUDIO_TRACK: {
53
-            return {
54
-                ...state,
55
-                audioTrack: action.value
56
-            };
57
-        }
58
-
59
-        case ADD_PREJOIN_CONTENT_SHARING_TRACK: {
60
-            return {
61
-                ...state,
62
-                contentSharingTrack: action.value
63
-            };
64
-        }
65
-
66
-        case ADD_PREJOIN_VIDEO_TRACK: {
67
-            return {
68
-                ...state,
69
-                videoTrack: action.value
70
-            };
71
-        }
72 38
 
73 39
         case SET_SKIP_PREJOIN: {
74 40
             return {
@@ -83,25 +49,6 @@ ReducerRegistry.register(
83 49
                 showPrejoin: action.value
84 50
             };
85 51
 
86
-        case SET_PREJOIN_VIDEO_DISABLED: {
87
-            return {
88
-                ...state,
89
-                videoDisabled: action.value
90
-            };
91
-        }
92
-
93
-        case SET_PREJOIN_VIDEO_MUTED:
94
-            return {
95
-                ...state,
96
-                videoMuted: action.value
97
-            };
98
-
99
-        case SET_PREJOIN_AUDIO_MUTED:
100
-            return {
101
-                ...state,
102
-                audioMuted: action.value
103
-            };
104
-
105 52
         case SET_PREJOIN_DEVICE_ERRORS: {
106 53
             const status = getStatusFromErrors(action.value);
107 54
 
@@ -119,13 +66,6 @@ ReducerRegistry.register(
119 66
             };
120 67
         }
121 68
 
122
-        case SET_PREJOIN_AUDIO_DISABLED: {
123
-            return {
124
-                ...state,
125
-                audioDisabled: true
126
-            };
127
-        }
128
-
129 69
         case SET_DIALOUT_NUMBER: {
130 70
             return {
131 71
                 ...state,

+ 2
- 17
react/features/toolbox/components/AudioMuteButton.js Zobrazit soubor

@@ -12,11 +12,6 @@ import { connect } from '../../base/redux';
12 12
 import { AbstractAudioMuteButton } from '../../base/toolbox';
13 13
 import type { AbstractButtonProps } from '../../base/toolbox';
14 14
 import { isLocalTrackMuted } from '../../base/tracks';
15
-import {
16
-    isPrejoinAudioMuted,
17
-    isAudioDisabled,
18
-    isPrejoinPageVisible
19
-} from '../../prejoin/functions';
20 15
 import { muteLocal } from '../../remote-video-menu/actions';
21 16
 
22 17
 declare var APP: Object;
@@ -154,18 +149,8 @@ class AudioMuteButton extends AbstractAudioMuteButton<Props, *> {
154 149
  * }}
155 150
  */
156 151
 function _mapStateToProps(state): Object {
157
-    let _audioMuted;
158
-    let _disabled;
159
-
160
-    if (isPrejoinPageVisible(state)) {
161
-        _audioMuted = isPrejoinAudioMuted(state);
162
-        _disabled = state['features/base/config'].startSilent;
163
-    } else {
164
-        const tracks = state['features/base/tracks'];
165
-
166
-        _audioMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.AUDIO);
167
-        _disabled = state['features/base/config'].startSilent || isAudioDisabled(state);
168
-    }
152
+    const _audioMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO);
153
+    const _disabled = state['features/base/config'].startSilent;
169 154
 
170 155
     return {
171 156
         _audioMuted,

+ 3
- 14
react/features/toolbox/components/VideoMuteButton.js Zobrazit soubor

@@ -9,6 +9,7 @@ import {
9 9
     sendAnalytics
10 10
 } from '../../analytics';
11 11
 import { setAudioOnly } from '../../base/audio-only';
12
+import { hasAvailableDevices } from '../../base/devices';
12 13
 import { translate } from '../../base/i18n';
13 14
 import {
14 15
     VIDEO_MUTISM_AUTHORITY,
@@ -18,11 +19,6 @@ import { connect } from '../../base/redux';
18 19
 import { AbstractVideoMuteButton } from '../../base/toolbox';
19 20
 import type { AbstractButtonProps } from '../../base/toolbox';
20 21
 import { getLocalVideoType, isLocalVideoTrackMuted } from '../../base/tracks';
21
-import {
22
-    isPrejoinPageVisible,
23
-    isPrejoinVideoDisabled,
24
-    isPrejoinVideoMuted
25
-} from '../../prejoin/functions';
26 22
 
27 23
 declare var APP: Object;
28 24
 
@@ -191,19 +187,12 @@ class VideoMuteButton extends AbstractVideoMuteButton<Props, *> {
191 187
 function _mapStateToProps(state): Object {
192 188
     const { enabled: audioOnly } = state['features/base/audio-only'];
193 189
     const tracks = state['features/base/tracks'];
194
-    let _videoMuted = isLocalVideoTrackMuted(tracks);
195
-    let _videoDisabled = false;
196
-
197
-    if (isPrejoinPageVisible(state)) {
198
-        _videoMuted = isPrejoinVideoMuted(state);
199
-        _videoDisabled = isPrejoinVideoDisabled(state);
200
-    }
201 190
 
202 191
     return {
203 192
         _audioOnly: Boolean(audioOnly),
204
-        _videoDisabled,
193
+        _videoDisabled: !hasAvailableDevices(state, 'videoInput'),
205 194
         _videoMediaType: getLocalVideoType(tracks),
206
-        _videoMuted
195
+        _videoMuted: isLocalVideoTrackMuted(tracks)
207 196
     };
208 197
 }
209 198
 

+ 20
- 3
react/features/toolbox/components/web/VideoSettingsButton.js Zobrazit soubor

@@ -6,6 +6,7 @@ import { IconArrowDown } from '../../../base/icons';
6 6
 import JitsiMeetJS from '../../../base/lib-jitsi-meet/_';
7 7
 import { connect } from '../../../base/redux';
8 8
 import { ToolboxButtonWithIcon } from '../../../base/toolbox';
9
+import { getLocalJitsiVideoTrack } from '../../../base/tracks';
9 10
 import { getMediaPermissionPromptVisibility } from '../../../overlay';
10 11
 import { toggleVideoSettings, VideoSettingsPopup } from '../../../settings';
11 12
 import { isVideoSettingsButtonDisabled } from '../../functions';
@@ -24,6 +25,11 @@ type Props = {
24 25
      */
25 26
     permissionPromptVisibility: boolean,
26 27
 
28
+    /**
29
+     * Whether there is a video track or not.
30
+     */
31
+    hasVideoTrack: boolean,
32
+
27 33
     /**
28 34
      * If the button should be disabled
29 35
      */
@@ -66,6 +72,17 @@ class VideoSettingsButton extends Component<Props, State> {
66 72
         };
67 73
     }
68 74
 
75
+    /**
76
+     * Returns true if the settings icon is disabled.
77
+     *
78
+     * @returns {boolean}
79
+     */
80
+    _isIconDisabled() {
81
+        const { hasVideoTrack, isDisabled } = this.props;
82
+
83
+        return (!this.state.hasPermissions || isDisabled) && !hasVideoTrack;
84
+    }
85
+
69 86
     /**
70 87
      * Updates device permissions.
71 88
      *
@@ -116,14 +133,13 @@ class VideoSettingsButton extends Component<Props, State> {
116 133
      * @inheritdoc
117 134
      */
118 135
     render() {
119
-        const { isDisabled, onVideoOptionsClick, visible } = this.props;
120
-        const iconDisabled = !this.state.hasPermissions || isDisabled;
136
+        const { onVideoOptionsClick, visible } = this.props;
121 137
 
122 138
         return visible ? (
123 139
             <VideoSettingsPopup>
124 140
                 <ToolboxButtonWithIcon
125 141
                     icon = { IconArrowDown }
126
-                    iconDisabled = { iconDisabled }
142
+                    iconDisabled = { this._isIconDisabled() }
127 143
                     onIconClick = { onVideoOptionsClick }>
128 144
                     <VideoMuteButton />
129 145
                 </ToolboxButtonWithIcon>
@@ -140,6 +156,7 @@ class VideoSettingsButton extends Component<Props, State> {
140 156
  */
141 157
 function mapStateToProps(state) {
142 158
     return {
159
+        hasVideoTrack: Boolean(getLocalJitsiVideoTrack(state)),
143 160
         isDisabled: isVideoSettingsButtonDisabled(state),
144 161
         permissionPromptVisibility: getMediaPermissionPromptVisibility(state)
145 162
     };

+ 4
- 16
react/features/toolbox/functions.web.js Zobrazit soubor

@@ -1,11 +1,6 @@
1 1
 // @flow
2 2
 
3 3
 import { hasAvailableDevices } from '../base/devices';
4
-import {
5
-    isAudioDisabled,
6
-    isPrejoinPageVisible,
7
-    isPrejoinVideoDisabled
8
-} from '../prejoin';
9 4
 
10 5
 declare var interfaceConfig: Object;
11 6
 
@@ -60,12 +55,9 @@ export function isToolboxVisible(state: Object) {
60 55
  * @returns {boolean}
61 56
  */
62 57
 export function isAudioSettingsButtonDisabled(state: Object) {
63
-    const devicesMissing = !hasAvailableDevices(state, 'audioInput')
64
-          && !hasAvailableDevices(state, 'audioOutput');
65
-
66
-    return isPrejoinPageVisible(state)
67
-        ? devicesMissing || isAudioDisabled(state)
68
-        : devicesMissing;
58
+    return (!hasAvailableDevices(state, 'audioInput')
59
+          && !hasAvailableDevices(state, 'audioOutput'))
60
+          || state['features/base/config'].startSilent;
69 61
 }
70 62
 
71 63
 /**
@@ -75,9 +67,5 @@ export function isAudioSettingsButtonDisabled(state: Object) {
75 67
  * @returns {boolean}
76 68
  */
77 69
 export function isVideoSettingsButtonDisabled(state: Object) {
78
-    const devicesMissing = !hasAvailableDevices(state, 'videoInput');
79
-
80
-    return isPrejoinPageVisible(state)
81
-        ? devicesMissing || isPrejoinVideoDisabled(state)
82
-        : devicesMissing;
70
+    return !hasAvailableDevices(state, 'videoInput');
83 71
 }

Načítá se…
Zrušit
Uložit