Selaa lähdekoodia

Proper use of getPropertyValue in base/media

master
zbettenbuk 7 vuotta sitten
vanhempi
commit
e30d141cec

+ 100
- 39
react/features/base/media/middleware.js Näytä tiedosto

@@ -1,4 +1,4 @@
1
-/* @flow */
1
+// @flow
2 2
 
3 3
 import {
4 4
     createStartAudioOnlyEvent,
@@ -6,7 +6,7 @@ import {
6 6
     createSyncTrackStateEvent,
7 7
     sendAnalytics
8 8
 } from '../../analytics';
9
-import { SET_ROOM, setAudioOnly } from '../conference';
9
+import { isRoomValid, SET_ROOM, setAudioOnly } from '../conference';
10 10
 import JitsiMeetJS from '../lib-jitsi-meet';
11 11
 import { getPropertyValue } from '../profile';
12 12
 import { MiddlewareRegistry } from '../redux';
@@ -14,6 +14,10 @@ import { setTrackMuted, TRACK_ADDED } from '../tracks';
14 14
 
15 15
 import { setAudioMuted, setCameraFacingMode, setVideoMuted } from './actions';
16 16
 import { CAMERA_FACING_MODE } from './constants';
17
+import {
18
+    _AUDIO_INITIAL_MEDIA_STATE,
19
+    _VIDEO_INITIAL_MEDIA_STATE
20
+} from './reducer';
17 21
 
18 22
 const logger = require('jitsi-meet-logger').getLogger(__filename);
19 23
 
@@ -30,8 +34,9 @@ MiddlewareRegistry.register(store => next => action => {
30 34
 
31 35
     case TRACK_ADDED: {
32 36
         const result = next(action);
37
+        const { track } = action;
33 38
 
34
-        action.track.local && _syncTrackMutedState(store, action.track);
39
+        track.local && _syncTrackMutedState(store, track);
35 40
 
36 41
         return result;
37 42
     }
@@ -55,25 +60,51 @@ MiddlewareRegistry.register(store => next => action => {
55 60
  * specified {@code action}.
56 61
  */
57 62
 function _setRoom({ dispatch, getState }, next, action) {
58
-    const { room } = action;
59
-
60
-    // Read the config.
63
+    // Figure out the desires/intents i.e. the state of base/media. There are
64
+    // multiple desires/intents ordered by precedence such as server-side
65
+    // config, config overrides in the user-supplied URL, user's own app
66
+    // settings, etc.
61 67
 
62 68
     const state = getState();
63
-    const hasRoom = Boolean(room);
64
-
65
-    const audioMuted = Boolean(getPropertyValue(state, 'startWithAudioMuted', {
66
-        urlParams: hasRoom
67
-    }));
68
-    const videoMuted = Boolean(getPropertyValue(state, 'startWithVideoMuted', {
69
-        urlParams: hasRoom
70
-    }));
71
-
72
-    sendAnalytics(createStartMutedConfigurationEvent(
73
-        'local', audioMuted, videoMuted));
74
-
75
-    logger.log(`Start muted: ${audioMuted ? 'audio, ' : ''}${
76
-        videoMuted ? 'video' : ''}`);
69
+    const { room } = action;
70
+    const roomIsValid = isRoomValid(room);
71
+
72
+    // XXX The configurations/preferences/settings startWithAudioMuted,
73
+    // startWithVideoMuted, and startAudioOnly were introduced for
74
+    // conferences/meetings. So it makes sense for these to not be considered
75
+    // outside of conferences/meetings (e.g. WelcomePage). Later on, though, we
76
+    // introduced a "Video <-> Voice" toggle on the WelcomePage which utilizes
77
+    // startAudioOnly outside of conferences/meetings so that particular
78
+    // configuration/preference/setting employs slightly exclusive logic.
79
+    const mutedSources = {
80
+        // We have startWithAudioMuted and startWithVideoMuted here:
81
+        config: true,
82
+        profile: true,
83
+
84
+        // XXX We've already overwritten base/config with urlParams. However,
85
+        // profile is more important than the server-side config. Consequently,
86
+        // we need to read from urlParams anyway:
87
+        urlParams: true,
88
+
89
+        // We don't have startWithAudioMuted and startWithVideoMuted here:
90
+        jwt: false
91
+    };
92
+    const audioMuted
93
+        = roomIsValid
94
+            ? Boolean(
95
+                getPropertyValue(state, 'startWithAudioMuted', mutedSources))
96
+            : _AUDIO_INITIAL_MEDIA_STATE.muted;
97
+    const videoMuted
98
+        = roomIsValid
99
+            ? Boolean(
100
+                getPropertyValue(state, 'startWithVideoMuted', mutedSources))
101
+            : _VIDEO_INITIAL_MEDIA_STATE.muted;
102
+
103
+    sendAnalytics(
104
+        createStartMutedConfigurationEvent('local', audioMuted, videoMuted));
105
+    logger.log(
106
+        `Start muted: ${audioMuted ? 'audio, ' : ''}${
107
+            videoMuted ? 'video' : ''}`);
77 108
 
78 109
     // Unconditionally express the desires/expectations/intents of the app and
79 110
     // the user i.e. the state of base/media. Eventually, practice/reality i.e.
@@ -82,29 +113,57 @@ function _setRoom({ dispatch, getState }, next, action) {
82 113
     dispatch(setCameraFacingMode(CAMERA_FACING_MODE.USER));
83 114
     dispatch(setVideoMuted(videoMuted));
84 115
 
85
-    // config.startAudioOnly
116
+    // startAudioOnly
86 117
     //
87 118
     // FIXME Technically, the audio-only feature is owned by base/conference,
88 119
     // not base/media so the following should be in base/conference.
89 120
     // Practically, I presume it was easier to write the source code here
90
-    // because it looks like config.startWithAudioMuted and
91
-    // config.startWithVideoMuted.
92
-    if (room) {
93
-        let audioOnly;
94
-
95
-        if (JitsiMeetJS.mediaDevices.supportsVideo()) {
96
-            audioOnly = Boolean(getPropertyValue(state, 'startAudioOnly'));
97
-        } else {
98
-            // Always default to being audio only if the current environment
99
-            // does not support sending or receiving video.
100
-            audioOnly = true;
101
-        }
102
-
103
-        sendAnalytics(createStartAudioOnlyEvent(audioOnly));
104
-        logger.log(`Start audio only set to ${audioOnly.toString()}`);
105
-        dispatch(setAudioOnly(audioOnly));
121
+    // because it looks like startWithAudioMuted and startWithVideoMuted.
122
+    //
123
+    // XXX After the introduction of the "Video <-> Voice" toggle on the
124
+    // WelcomePage, startAudioOnly is utilized even outside of
125
+    // conferences/meetings.
126
+    let audioOnly;
127
+
128
+    if (JitsiMeetJS.mediaDevices.supportsVideo()) {
129
+        audioOnly
130
+            = Boolean(
131
+                getPropertyValue(
132
+                    state,
133
+                    'startAudioOnly',
134
+                    /* sources */ {
135
+                        // FIXME Practically, base/config is (really) correct
136
+                        // only if roomIsValid. At the time of this writing,
137
+                        // base/config is overwritten by URL params which leaves
138
+                        // base/config incorrect on the WelcomePage after
139
+                        // leaving a conference which explicitly overwrites
140
+                        // base/config with URL params.
141
+                        config: roomIsValid,
142
+
143
+                        // XXX We've already overwritten base/config with
144
+                        // urlParams if roomIsValid. However, profile is more
145
+                        // important than the server-side config. Consequently,
146
+                        // we need to read from urlParams anyway. We also
147
+                        // probably want to read from urlParams when
148
+                        // !roomIsValid.
149
+                        urlParams: true,
150
+
151
+                        // The following don't have complications around whether
152
+                        // they are defined or not:
153
+                        jwt: false,
154
+                        profile: true
155
+                    }));
156
+    } else {
157
+        // Default to audio-only if the (execution) environment does not
158
+        // support (sending and/or receiving) video.
159
+        audioOnly = true;
106 160
     }
107 161
 
162
+    sendAnalytics(createStartAudioOnlyEvent(audioOnly));
163
+    logger.log(`Start audio only set to ${audioOnly.toString()}`);
164
+
165
+    dispatch(setAudioOnly(audioOnly));
166
+
108 167
     return next(action);
109 168
 }
110 169
 
@@ -127,8 +186,10 @@ function _syncTrackMutedState({ getState }, track) {
127 186
     // fired before track gets to state.
128 187
     if (track.muted !== muted) {
129 188
         sendAnalytics(createSyncTrackStateEvent(track.mediaType, muted));
130
-        logger.log(`Sync ${track.mediaType} track muted state to ${
131
-            muted ? 'muted' : 'unmuted'}`);
189
+        logger.log(
190
+            `Sync ${track.mediaType} track muted state to ${
191
+                muted ? 'muted' : 'unmuted'}`);
192
+
132 193
         track.muted = muted;
133 194
         setTrackMuted(track.jitsiTrack, muted);
134 195
     }

+ 13
- 5
react/features/base/media/reducer.js Näytä tiedosto

@@ -22,12 +22,16 @@ import { CAMERA_FACING_MODE } from './constants';
22 22
  * @property {boolean} muted=false - Audio muted state.
23 23
  */
24 24
 
25
+// FIXME Technically, _AUDIO_INITIAL_MEDIA_STATE is a constant internal to the
26
+// feature base/media and used in multiple files so it should be in
27
+// constants.js. Practically though, AudioMediaState would then be used in
28
+// multiple files as well so I don't know where and how to move it.
25 29
 /**
26 30
  * Initial state for local audio.
27 31
  *
28 32
  * @type {AudioMediaState}
29 33
  */
30
-const AUDIO_INITIAL_MEDIA_STATE = {
34
+export const _AUDIO_INITIAL_MEDIA_STATE = {
31 35
     available: true,
32 36
     muted: false
33 37
 };
@@ -41,7 +45,7 @@ const AUDIO_INITIAL_MEDIA_STATE = {
41 45
  * @private
42 46
  * @returns {AudioMediaState}
43 47
  */
44
-function _audio(state = AUDIO_INITIAL_MEDIA_STATE, action) {
48
+function _audio(state = _AUDIO_INITIAL_MEDIA_STATE, action) {
45 49
     switch (action.type) {
46 50
     case SET_AUDIO_AVAILABLE:
47 51
         return {
@@ -68,12 +72,16 @@ function _audio(state = AUDIO_INITIAL_MEDIA_STATE, action) {
68 72
  * @property {boolean} muted=false - Video muted state.
69 73
  */
70 74
 
75
+// FIXME Technically, _VIDEO_INITIAL_MEDIA_STATE is a constant internal to the
76
+// feature base/media and used in multiple files so it should be in
77
+// constants.js. Practically though, VideoMediaState would then be used in
78
+// multiple files as well so I don't know where and how to move it.
71 79
 /**
72 80
  * Initial state for video.
73 81
  *
74 82
  * @type {VideoMediaState}
75 83
  */
76
-const VIDEO_INITIAL_MEDIA_STATE = {
84
+export const _VIDEO_INITIAL_MEDIA_STATE = {
77 85
     available: true,
78 86
     facingMode: CAMERA_FACING_MODE.USER,
79 87
     muted: 0,
@@ -94,7 +102,7 @@ const VIDEO_INITIAL_MEDIA_STATE = {
94 102
  * @private
95 103
  * @returns {VideoMediaState}
96 104
  */
97
-function _video(state = VIDEO_INITIAL_MEDIA_STATE, action) {
105
+function _video(state = _VIDEO_INITIAL_MEDIA_STATE, action) {
98 106
     switch (action.type) {
99 107
     case CONFERENCE_FAILED:
100 108
     case CONFERENCE_LEFT:
@@ -168,7 +176,7 @@ ReducerRegistry.register('features/base/media', combineReducers({
168 176
 function _clearAllVideoTransforms(state) {
169 177
     return {
170 178
         ...state,
171
-        transforms: VIDEO_INITIAL_MEDIA_STATE.transforms
179
+        transforms: _VIDEO_INITIAL_MEDIA_STATE.transforms
172 180
     };
173 181
 }
174 182
 

+ 8
- 5
react/features/base/profile/middleware.js Näytä tiedosto

@@ -7,7 +7,9 @@ import { MiddlewareRegistry, toState } from '../redux';
7 7
 import { PROFILE_UPDATED } from './actionTypes';
8 8
 
9 9
 /**
10
- * A middleWare to update the local participant when the profile is updated.
10
+ * The middleware of the feature base/profile. Distributes changes to the state
11
+ * of base/profile to the states of other features computed from the state of
12
+ * base/profile.
11 13
  *
12 14
  * @param {Store} store - The redux store.
13 15
  * @returns {Function}
@@ -18,21 +20,21 @@ MiddlewareRegistry.register(store => next => action => {
18 20
     switch (action.type) {
19 21
     case PROFILE_UPDATED:
20 22
         _updateLocalParticipant(store);
21
-        _maybeUpdateStartAudioOnly(store, action);
23
+        _maybeSetAudioOnly(store, action);
22 24
     }
23 25
 
24 26
     return result;
25 27
 });
26 28
 
27 29
 /**
28
- * Updates startAudioOnly flag if it's updated in the profile.
30
+ * Updates {@code startAudioOnly} flag if it's updated in the profile.
29 31
  *
30
- * @private
31 32
  * @param {Store} store - The redux store.
32 33
  * @param {Object} action - The redux action.
34
+ * @private
33 35
  * @returns {void}
34 36
  */
35
-function _maybeUpdateStartAudioOnly(
37
+function _maybeSetAudioOnly(
36 38
         { dispatch },
37 39
         { profile: { startAudioOnly } }) {
38 40
     if (typeof startAudioOnly === 'boolean') {
@@ -44,6 +46,7 @@ function _maybeUpdateStartAudioOnly(
44 46
  * Updates the local participant according to profile changes.
45 47
  *
46 48
  * @param {Store} store - The redux store.
49
+ * @private
47 50
  * @returns {void}
48 51
  */
49 52
 function _updateLocalParticipant(store) {

Loading…
Peruuta
Tallenna