Przeglądaj źródła

[RN] base/media is intent, base/tracks is reality

j8
Lyubo Marinov 8 lat temu
rodzic
commit
85a168d51b

+ 8
- 4
react/features/base/conference/actions.js Wyświetl plik

62
 
62
 
63
     // Dispatches into features/base/media follow:
63
     // Dispatches into features/base/media follow:
64
 
64
 
65
-    // FIXME: This is needed because when Jicofo tells us to start muted
66
-    // lib-jitsi-meet does the actual muting. Perhaps this should be refactored
67
-    // so applications are hinted to start muted, but lib-jitsi-meet doesn't
68
-    // take action.
69
     conference.on(
65
     conference.on(
70
         JitsiConferenceEvents.STARTED_MUTED,
66
         JitsiConferenceEvents.STARTED_MUTED,
71
         () => {
67
         () => {
68
+            // XXX Jicofo tells lib-jitsi-meet to start with audio and/or video
69
+            // muted i.e. Jicofo expresses an intent. Lib-jitsi-meet has turned
70
+            // Jicofo's intent into reality by actually muting the respective
71
+            // tracks. The reality is expressed in base/tracks already so what
72
+            // is left is to express Jicofo's intent in base/media.
73
+            // TODO Maybe the app needs to learn about Jicofo's intent and
74
+            // transfer that intent to lib-jitsi-meet instead of lib-jitsi-meet
75
+            // acting on Jicofo's intent without the app's knowledge.
72
             dispatch(setAudioMuted(Boolean(conference.startAudioMuted)));
76
             dispatch(setAudioMuted(Boolean(conference.startAudioMuted)));
73
             dispatch(setVideoMuted(Boolean(conference.startVideoMuted)));
77
             dispatch(setVideoMuted(Boolean(conference.startVideoMuted)));
74
         });
78
         });

+ 39
- 39
react/features/base/conference/middleware.js Wyświetl plik

32
 /**
32
 /**
33
  * Implements the middleware of the feature base/conference.
33
  * Implements the middleware of the feature base/conference.
34
  *
34
  *
35
- * @param {Store} store - Redux store.
35
+ * @param {Store} store - The redux store.
36
  * @returns {Function}
36
  * @returns {Function}
37
  */
37
  */
38
 MiddlewareRegistry.register(store => next => action => {
38
 MiddlewareRegistry.register(store => next => action => {
40
     case CONNECTION_ESTABLISHED:
40
     case CONNECTION_ESTABLISHED:
41
         return _connectionEstablished(store, next, action);
41
         return _connectionEstablished(store, next, action);
42
 
42
 
43
-    case CONFERENCE_JOINED:
44
-        return _conferenceJoined(store, next, action);
45
-
46
     case CONFERENCE_FAILED:
43
     case CONFERENCE_FAILED:
47
     case CONFERENCE_LEFT:
44
     case CONFERENCE_LEFT:
48
         return _conferenceFailedOrLeft(store, next, action);
45
         return _conferenceFailedOrLeft(store, next, action);
49
 
46
 
47
+    case CONFERENCE_JOINED:
48
+        return _conferenceJoined(store, next, action);
49
+
50
     case PIN_PARTICIPANT:
50
     case PIN_PARTICIPANT:
51
         return _pinParticipant(store, next, action);
51
         return _pinParticipant(store, next, action);
52
 
52
 
66
 
66
 
67
 /**
67
 /**
68
  * Notifies the feature base/conference that the action CONNECTION_ESTABLISHED
68
  * Notifies the feature base/conference that the action CONNECTION_ESTABLISHED
69
- * is being dispatched within a specific Redux store.
69
+ * is being dispatched within a specific redux store.
70
  *
70
  *
71
- * @param {Store} store - The Redux store in which the specified action is being
71
+ * @param {Store} store - The redux store in which the specified action is being
72
  * dispatched.
72
  * dispatched.
73
- * @param {Dispatch} next - The Redux dispatch function to dispatch the
73
+ * @param {Dispatch} next - The redux dispatch function to dispatch the
74
  * specified action to the specified store.
74
  * specified action to the specified store.
75
- * @param {Action} action - The Redux action CONNECTION_ESTABLISHED which is
75
+ * @param {Action} action - The redux action CONNECTION_ESTABLISHED which is
76
  * being dispatched in the specified store.
76
  * being dispatched in the specified store.
77
  * @private
77
  * @private
78
  * @returns {Object} The new state that is the result of the reduction of the
78
  * @returns {Object} The new state that is the result of the reduction of the
91
 }
91
 }
92
 
92
 
93
 /**
93
 /**
94
- * Does extra sync up on properties that may need to be updated, after
95
- * the conference failed or was left.
94
+ * Does extra sync up on properties that may need to be updated after the
95
+ * conference failed or was left.
96
  *
96
  *
97
- * @param {Store} store - The Redux store in which the specified action is being
97
+ * @param {Store} store - The redux store in which the specified action is being
98
  * dispatched.
98
  * dispatched.
99
- * @param {Dispatch} next - The Redux dispatch function to dispatch the
99
+ * @param {Dispatch} next - The redux dispatch function to dispatch the
100
  * specified action to the specified store.
100
  * specified action to the specified store.
101
- * @param {Action} action - The Redux action {@link CONFERENCE_FAILED} or
101
+ * @param {Action} action - The redux action {@link CONFERENCE_FAILED} or
102
  * {@link CONFERENCE_LEFT} which is being dispatched in the specified store.
102
  * {@link CONFERENCE_LEFT} which is being dispatched in the specified store.
103
  * @private
103
  * @private
104
  * @returns {Object} The new state that is the result of the reduction of the
104
  * @returns {Object} The new state that is the result of the reduction of the
105
  * specified action.
105
  * specified action.
106
  */
106
  */
107
-function _conferenceFailedOrLeft(store, next, action) {
107
+function _conferenceFailedOrLeft({ dispatch, getState }, next, action) {
108
     const result = next(action);
108
     const result = next(action);
109
-    const { audioOnly } = store.getState()['features/base/conference'];
110
 
109
 
111
-    audioOnly && store.dispatch(setAudioOnly(false));
110
+    getState()['features/base/conference'].audioOnly
111
+        && dispatch(setAudioOnly(false));
112
 
112
 
113
     return result;
113
     return result;
114
 }
114
 }
115
 
115
 
116
 /**
116
 /**
117
- * Does extra sync up on properties that may need to be updated, after
118
- * the conference was joined.
117
+ * Does extra sync up on properties that may need to be updated after the
118
+ * conference was joined.
119
  *
119
  *
120
- * @param {Store} store - The Redux store in which the specified action is being
120
+ * @param {Store} store - The redux store in which the specified action is being
121
  * dispatched.
121
  * dispatched.
122
- * @param {Dispatch} next - The Redux dispatch function to dispatch the
122
+ * @param {Dispatch} next - The redux dispatch function to dispatch the
123
  * specified action to the specified store.
123
  * specified action to the specified store.
124
- * @param {Action} action - The Redux action CONFERENCE_JOINED which is being
124
+ * @param {Action} action - The redux action CONFERENCE_JOINED which is being
125
  * dispatched in the specified store.
125
  * dispatched in the specified store.
126
  * @private
126
  * @private
127
  * @returns {Object} The new state that is the result of the reduction of the
127
  * @returns {Object} The new state that is the result of the reduction of the
144
 
144
 
145
 /**
145
 /**
146
  * Notifies the feature base/conference that the action PIN_PARTICIPANT is being
146
  * Notifies the feature base/conference that the action PIN_PARTICIPANT is being
147
- * dispatched within a specific Redux store. Pins the specified remote
147
+ * dispatched within a specific redux store. Pins the specified remote
148
  * participant in the associated conference, ignores the local participant.
148
  * participant in the associated conference, ignores the local participant.
149
  *
149
  *
150
- * @param {Store} store - The Redux store in which the specified action is being
150
+ * @param {Store} store - The redux store in which the specified action is being
151
  * dispatched.
151
  * dispatched.
152
- * @param {Dispatch} next - The Redux dispatch function to dispatch the
152
+ * @param {Dispatch} next - The redux dispatch function to dispatch the
153
  * specified action to the specified store.
153
  * specified action to the specified store.
154
- * @param {Action} action - The Redux action PIN_PARTICIPANT which is being
154
+ * @param {Action} action - The redux action PIN_PARTICIPANT which is being
155
  * dispatched in the specified store.
155
  * dispatched in the specified store.
156
  * @private
156
  * @private
157
  * @returns {Object} The new state that is the result of the reduction of the
157
  * @returns {Object} The new state that is the result of the reduction of the
195
  * Sets the audio-only flag for the current conference. When audio-only is set,
195
  * Sets the audio-only flag for the current conference. When audio-only is set,
196
  * local video is muted and last N is set to 0 to avoid receiving remote video.
196
  * local video is muted and last N is set to 0 to avoid receiving remote video.
197
  *
197
  *
198
- * @param {Store} store - The Redux store in which the specified action is being
198
+ * @param {Store} store - The redux store in which the specified action is being
199
  * dispatched.
199
  * dispatched.
200
- * @param {Dispatch} next - The Redux dispatch function to dispatch the
200
+ * @param {Dispatch} next - The redux dispatch function to dispatch the
201
  * specified action to the specified store.
201
  * specified action to the specified store.
202
- * @param {Action} action - The Redux action SET_AUDIO_ONLY which is being
202
+ * @param {Action} action - The redux action SET_AUDIO_ONLY which is being
203
  * dispatched in the specified store.
203
  * dispatched in the specified store.
204
  * @private
204
  * @private
205
  * @returns {Object} The new state that is the result of the reduction of the
205
  * @returns {Object} The new state that is the result of the reduction of the
206
  * specified action.
206
  * specified action.
207
  */
207
  */
208
-function _setAudioOnly({ dispatch }, next, action) {
208
+function _setAudioOnly({ dispatch, getState }, next, action) {
209
     const result = next(action);
209
     const result = next(action);
210
 
210
 
211
-    const { audioOnly } = action;
211
+    const { audioOnly } = getState()['features/base/conference'];
212
 
212
 
213
     // Set lastN to 0 in case audio-only is desired; leave it as undefined,
213
     // Set lastN to 0 in case audio-only is desired; leave it as undefined,
214
     // otherwise, and the default lastN value will be chosen automatically.
214
     // otherwise, and the default lastN value will be chosen automatically.
215
     dispatch(setLastN(audioOnly ? 0 : undefined));
215
     dispatch(setLastN(audioOnly ? 0 : undefined));
216
 
216
 
217
-    // Mute the local video.
217
+    // Mute/unmute the local video.
218
     dispatch(setVideoMuted(audioOnly, VIDEO_MUTISM_AUTHORITY.AUDIO_ONLY));
218
     dispatch(setVideoMuted(audioOnly, VIDEO_MUTISM_AUTHORITY.AUDIO_ONLY));
219
 
219
 
220
     if (typeof APP !== 'undefined') {
220
     if (typeof APP !== 'undefined') {
229
 /**
229
 /**
230
  * Sets the last N (value) of the video channel in the conference.
230
  * Sets the last N (value) of the video channel in the conference.
231
  *
231
  *
232
- * @param {Store} store - The Redux store in which the specified action is being
232
+ * @param {Store} store - The redux store in which the specified action is being
233
  * dispatched.
233
  * dispatched.
234
- * @param {Dispatch} next - The Redux dispatch function to dispatch the
234
+ * @param {Dispatch} next - The redux dispatch function to dispatch the
235
  * specified action to the specified store.
235
  * specified action to the specified store.
236
- * @param {Action} action - The Redux action SET_LASTN which is being dispatched
236
+ * @param {Action} action - The redux action SET_LASTN which is being dispatched
237
  * in the specified store.
237
  * in the specified store.
238
  * @private
238
  * @private
239
  * @returns {Object} The new state that is the result of the reduction of the
239
  * @returns {Object} The new state that is the result of the reduction of the
257
  * Synchronizes local tracks from state with local tracks in JitsiConference
257
  * Synchronizes local tracks from state with local tracks in JitsiConference
258
  * instance.
258
  * instance.
259
  *
259
  *
260
- * @param {Store} store - Redux store.
260
+ * @param {Store} store - The redux store.
261
  * @param {Object} action - Action object.
261
  * @param {Object} action - Action object.
262
  * @private
262
  * @private
263
  * @returns {Promise}
263
  * @returns {Promise}
284
 
284
 
285
 /**
285
 /**
286
  * Notifies the feature base/conference that the action TRACK_ADDED
286
  * Notifies the feature base/conference that the action TRACK_ADDED
287
- * or TRACK_REMOVED is being dispatched within a specific Redux store.
287
+ * or TRACK_REMOVED is being dispatched within a specific redux store.
288
  *
288
  *
289
- * @param {Store} store - The Redux store in which the specified action is being
289
+ * @param {Store} store - The redux store in which the specified action is being
290
  * dispatched.
290
  * dispatched.
291
- * @param {Dispatch} next - The Redux dispatch function to dispatch the
291
+ * @param {Dispatch} next - The redux dispatch function to dispatch the
292
  * specified action to the specified store.
292
  * specified action to the specified store.
293
- * @param {Action} action - The Redux action TRACK_ADDED or TRACK_REMOVED which
293
+ * @param {Action} action - The redux action TRACK_ADDED or TRACK_REMOVED which
294
  * is being dispatched in the specified store.
294
  * is being dispatched in the specified store.
295
  * @private
295
  * @private
296
  * @returns {Object} The new state that is the result of the reduction of the
296
  * @returns {Object} The new state that is the result of the reduction of the

+ 6
- 7
react/features/base/media/middleware.js Wyświetl plik

72
         && (videoMuted = config.startWithVideoMuted);
72
         && (videoMuted = config.startWithVideoMuted);
73
 
73
 
74
     // Apply startWithAudioMuted and startWithVideoMuted.
74
     // Apply startWithAudioMuted and startWithVideoMuted.
75
-    const { audio, video } = state['features/base/media'];
76
-
77
     audioMuted = Boolean(audioMuted);
75
     audioMuted = Boolean(audioMuted);
78
     videoMuted = Boolean(videoMuted);
76
     videoMuted = Boolean(videoMuted);
79
 
77
 
80
-    (audio.muted !== audioMuted) && dispatch(setAudioMuted(audioMuted));
81
-    (video.facingMode !== CAMERA_FACING_MODE.USER)
82
-        && dispatch(setCameraFacingMode(CAMERA_FACING_MODE.USER));
83
-    (Boolean(video.muted) !== videoMuted)
84
-        && dispatch(setVideoMuted(videoMuted));
78
+    // Unconditionally express the desires/expectations/intents of the app and
79
+    // the user i.e. the state of base/media. Eventually, practice/reality i.e.
80
+    // the state of base/tracks will or will not agree with the desires.
81
+    dispatch(setAudioMuted(audioMuted));
82
+    dispatch(setCameraFacingMode(CAMERA_FACING_MODE.USER));
83
+    dispatch(setVideoMuted(videoMuted));
85
 
84
 
86
     return next(action);
85
     return next(action);
87
 }
86
 }

+ 30
- 17
react/features/base/tracks/actions.js Wyświetl plik

87
  */
87
  */
88
 export function replaceLocalTrack(oldTrack, newTrack, conference) {
88
 export function replaceLocalTrack(oldTrack, newTrack, conference) {
89
     return (dispatch, getState) => {
89
     return (dispatch, getState) => {
90
-        const currentConference = conference
91
-            || getState()['features/base/conference'].conference;
90
+        conference
92
 
91
 
93
-        return currentConference.replaceTrack(oldTrack, newTrack)
92
+            // eslint-disable-next-line no-param-reassign
93
+            || (conference = getState()['features/base/conference'].conference);
94
+
95
+        return conference.replaceTrack(oldTrack, newTrack)
94
             .then(() => {
96
             .then(() => {
95
-                // We call dispose after doing the replace because
96
-                //  dispose will try and do a new o/a after the
97
-                //  track removes itself.  Doing it after means
98
-                //  the JitsiLocalTrack::conference member is already
99
-                //  cleared, so it won't try and do the o/a
100
-                const disposePromise = oldTrack
101
-                    ? dispatch(_disposeAndRemoveTracks([ oldTrack ]))
102
-                    : Promise.resolve();
97
+                // We call dispose after doing the replace because dispose will
98
+                // try and do a new o/a after the track removes itself. Doing it
99
+                // after means the JitsiLocalTrack.conference is already
100
+                // cleared, so it won't try and do the o/a.
101
+                const disposePromise
102
+                    = oldTrack
103
+                        ? dispatch(_disposeAndRemoveTracks([ oldTrack ]))
104
+                        : Promise.resolve();
103
 
105
 
104
                 return disposePromise
106
                 return disposePromise
105
                     .then(() => {
107
                     .then(() => {
113
                             // track's mute state. If this is not done, the
115
                             // track's mute state. If this is not done, the
114
                             // current mute state of the app will be reflected
116
                             // current mute state of the app will be reflected
115
                             // on the track, not vice-versa.
117
                             // on the track, not vice-versa.
116
-                            const muteAction = newTrack.isVideoTrack()
117
-                                ? setVideoMuted : setAudioMuted;
118
+                            const setMuted
119
+                                = newTrack.isVideoTrack()
120
+                                    ? setVideoMuted
121
+                                    : setAudioMuted;
118
 
122
 
119
-                            return dispatch(muteAction(newTrack.isMuted()));
123
+                            return dispatch(setMuted(newTrack.isMuted()));
120
                         }
124
                         }
121
                     })
125
                     })
122
                     .then(() => {
126
                     .then(() => {
366
 
370
 
367
         const f = muted ? 'mute' : 'unmute';
371
         const f = muted ? 'mute' : 'unmute';
368
 
372
 
369
-        // FIXME: This operation disregards the authority. It is not a problem
370
-        // (on mobile) at the moment, but it will be once we start not creating
371
-        // tracks early. Refactor this then.
372
         return track[f]().catch(error => {
373
         return track[f]().catch(error => {
373
             console.error(`set track ${f} failed`, error);
374
             console.error(`set track ${f} failed`, error);
374
 
375
 
376
+            if (navigator.product === 'ReactNative') {
377
+                // Synchronizing the state of base/tracks into the state of
378
+                // base/media is not required in React (and, respectively, React
379
+                // Native) because base/media expresses the app's and the user's
380
+                // desires/expectations/intents and base/tracks expresses
381
+                // practice/reality. Unfortunately, the old Web does not comply
382
+                // and/or does the opposite.
383
+                return;
384
+            }
385
+
375
             const setMuted
386
             const setMuted
376
                 = track.mediaType === MEDIA_TYPE.AUDIO
387
                 = track.mediaType === MEDIA_TYPE.AUDIO
377
                     ? setAudioMuted
388
                     ? setAudioMuted
378
                     : setVideoMuted;
389
                     : setVideoMuted;
379
 
390
 
391
+            // FIXME The following disregards VIDEO_MUTISM_AUTHORITY (in the
392
+            // case of setVideoMuted, of course).
380
             dispatch(setMuted(!muted));
393
             dispatch(setMuted(!muted));
381
         });
394
         });
382
     };
395
     };

+ 17
- 15
react/features/base/tracks/middleware.js Wyświetl plik

100
         break;
100
         break;
101
 
101
 
102
     case TRACK_UPDATED:
102
     case TRACK_UPDATED:
103
-        // TODO Remove the below calls to APP.UI once components interested in
104
-        // track mute changes are moved into react.
103
+        // TODO Remove the following calls to APP.UI once components interested
104
+        // in track mute changes are moved into React and/or redux.
105
         if (typeof APP !== 'undefined') {
105
         if (typeof APP !== 'undefined') {
106
             const { jitsiTrack } = action.track;
106
             const { jitsiTrack } = action.track;
107
-            const isMuted = jitsiTrack.isMuted();
107
+            const muted = jitsiTrack.isMuted();
108
             const participantID = jitsiTrack.getParticipantId();
108
             const participantID = jitsiTrack.getParticipantId();
109
             const isVideoTrack = jitsiTrack.isVideoTrack();
109
             const isVideoTrack = jitsiTrack.isVideoTrack();
110
 
110
 
111
             if (jitsiTrack.isLocal()) {
111
             if (jitsiTrack.isLocal()) {
112
                 if (isVideoTrack) {
112
                 if (isVideoTrack) {
113
-                    APP.conference.videoMuted = isMuted;
113
+                    APP.conference.videoMuted = muted;
114
                 } else {
114
                 } else {
115
-                    APP.conference.audioMuted = isMuted;
115
+                    APP.conference.audioMuted = muted;
116
                 }
116
                 }
117
             }
117
             }
118
 
118
 
119
             if (isVideoTrack) {
119
             if (isVideoTrack) {
120
-                APP.UI.setVideoMuted(participantID, isMuted);
120
+                APP.UI.setVideoMuted(participantID, muted);
121
                 APP.UI.onPeerVideoTypeChanged(
121
                 APP.UI.onPeerVideoTypeChanged(
122
-                    participantID, jitsiTrack.videoType);
122
+                    participantID,
123
+                    jitsiTrack.videoType);
123
             } else {
124
             } else {
124
-                APP.UI.setAudioMuted(participantID, isMuted);
125
+                APP.UI.setAudioMuted(participantID, muted);
125
             }
126
             }
126
 
127
 
127
-            // XXX This function synchronizes track states with media states.
128
-            // This is not required in React, because media is the source of
129
-            // truth, synchronization should always happen in the media -> track
130
-            // direction. The old web, however, does the opposite, hence the
131
-            // need for this.
128
+            // XXX The following synchronizes the state of base/tracks into the
129
+            // state of base/media. Which is not required in React (and,
130
+            // respectively, React Native) because base/media expresses the
131
+            // app's and the user's desires/expectations/intents and base/tracks
132
+            // expresses practice/reality. Unfortunately, the old Web does not
133
+            // comply and/or does the opposite. Hence, the following:
132
             return _trackUpdated(store, next, action);
134
             return _trackUpdated(store, next, action);
133
         }
135
         }
134
 
136
 
149
  * @returns {Track} The local <tt>Track</tt> associated with the specified
151
  * @returns {Track} The local <tt>Track</tt> associated with the specified
150
  * <tt>mediaType</tt> in the specified <tt>store</tt>.
152
  * <tt>mediaType</tt> in the specified <tt>store</tt>.
151
  */
153
  */
152
-function _getLocalTrack(store, mediaType: MEDIA_TYPE) {
153
-    return getLocalTrack(store.getState()['features/base/tracks'], mediaType);
154
+function _getLocalTrack({ getState }, mediaType: MEDIA_TYPE) {
155
+    return getLocalTrack(getState()['features/base/tracks'], mediaType);
154
 }
156
 }
155
 
157
 
156
 /**
158
 /**

+ 8
- 22
react/features/mobile/audio-mode/middleware.js Wyświetl plik

16
  * based on the type of conference. Audio-only conferences don't use the speaker
16
  * based on the type of conference. Audio-only conferences don't use the speaker
17
  * by default, and video conferences do.
17
  * by default, and video conferences do.
18
  *
18
  *
19
- * @param {Store} store - Redux store.
19
+ * @param {Store} store - The redux store.
20
  * @returns {Function}
20
  * @returns {Function}
21
  */
21
  */
22
-MiddlewareRegistry.register(store => next => action => {
22
+MiddlewareRegistry.register(({ getState }) => next => action => {
23
     const AudioMode = NativeModules.AudioMode;
23
     const AudioMode = NativeModules.AudioMode;
24
 
24
 
25
     if (AudioMode) {
25
     if (AudioMode) {
32
             mode = AudioMode.DEFAULT;
32
             mode = AudioMode.DEFAULT;
33
             break;
33
             break;
34
 
34
 
35
-        case CONFERENCE_WILL_JOIN: {
36
-            const { audioOnly } = store.getState()['features/base/conference'];
37
-
38
-            mode = audioOnly ? AudioMode.AUDIO_CALL : AudioMode.VIDEO_CALL;
39
-            break;
40
-        }
41
-
35
+        case CONFERENCE_WILL_JOIN:
42
         case SET_AUDIO_ONLY: {
36
         case SET_AUDIO_ONLY: {
43
-            const { conference } = store.getState()['features/base/conference'];
44
-
45
-            if (conference) {
37
+            if (getState()['features/base/conference'].conference
38
+                    || action.conference) {
46
                 mode
39
                 mode
47
                     = action.audioOnly
40
                     = action.audioOnly
48
-                    ? AudioMode.AUDIO_CALL
49
-                    : AudioMode.VIDEO_CALL;
50
-            } else {
51
-                mode = null;
41
+                        ? AudioMode.AUDIO_CALL
42
+                        : AudioMode.VIDEO_CALL;
52
             }
43
             }
53
-
54
             break;
44
             break;
55
         }
45
         }
56
-
57
-        default:
58
-            mode = null;
59
-            break;
60
         }
46
         }
61
 
47
 
62
-        if (mode !== null) {
48
+        if (typeof mode !== 'undefined') {
63
             AudioMode.setMode(mode)
49
             AudioMode.setMode(mode)
64
                 .catch(err =>
50
                 .catch(err =>
65
                     console.error(
51
                     console.error(

+ 2
- 5
react/features/mobile/background/actions.js Wyświetl plik

1
 import { setLastN } from '../../base/conference';
1
 import { setLastN } from '../../base/conference';
2
 import { setVideoMuted, VIDEO_MUTISM_AUTHORITY } from '../../base/media';
2
 import { setVideoMuted, VIDEO_MUTISM_AUTHORITY } from '../../base/media';
3
 
3
 
4
-import {
5
-    _SET_APP_STATE_LISTENER,
6
-    APP_STATE_CHANGED
7
-} from './actionTypes';
4
+import { _SET_APP_STATE_LISTENER, APP_STATE_CHANGED } from './actionTypes';
8
 
5
 
9
 /**
6
 /**
10
  * Sets the listener to be used with React Native's AppState API.
7
  * Sets the listener to be used with React Native's AppState API.
41
         // for last N will be chosen automatically.
38
         // for last N will be chosen automatically.
42
         const { audioOnly } = getState()['features/base/conference'];
39
         const { audioOnly } = getState()['features/base/conference'];
43
 
40
 
44
-        !audioOnly && dispatch(setLastN(muted ? 0 : undefined));
41
+        audioOnly || dispatch(setLastN(muted ? 0 : undefined));
45
         dispatch(setVideoMuted(muted, VIDEO_MUTISM_AUTHORITY.BACKGROUND));
42
         dispatch(setVideoMuted(muted, VIDEO_MUTISM_AUTHORITY.BACKGROUND));
46
     };
43
     };
47
 }
44
 }

+ 16
- 29
react/features/mobile/full-screen/middleware.js Wyświetl plik

22
  * In immersive mode the status and navigation bars are hidden and thus the
22
  * In immersive mode the status and navigation bars are hidden and thus the
23
  * entire screen will be covered by our application.
23
  * entire screen will be covered by our application.
24
  *
24
  *
25
- * @param {Store} store - Redux store.
25
+ * @param {Store} store - The redux store.
26
  * @returns {Function}
26
  * @returns {Function}
27
  */
27
  */
28
-MiddlewareRegistry.register(store => next => action => {
28
+MiddlewareRegistry.register(({ getState }) => next => action => {
29
+    const result = next(action);
30
+
29
     let fullScreen = null;
31
     let fullScreen = null;
30
 
32
 
31
     switch (action.type) {
33
     switch (action.type) {
32
-    case APP_STATE_CHANGED: {
33
-        // Check if we just came back from the background and reenable full
34
+    case APP_STATE_CHANGED:
35
+    case CONFERENCE_WILL_JOIN:
36
+    case HIDE_DIALOG:
37
+    case SET_AUDIO_ONLY: {
38
+        // Check if we just came back from the background and re-enable full
34
         // screen mode if necessary.
39
         // screen mode if necessary.
35
-        if (action.appState === 'active') {
36
-            const { audioOnly, conference }
37
-                = store.getState()['features/base/conference'];
40
+        const { appState } = action;
38
 
41
 
39
-            fullScreen = conference ? !audioOnly : false;
42
+        if (typeof appState !== 'undefined' && appState !== 'active') {
43
+            break;
40
         }
44
         }
41
-        break;
42
-    }
43
 
45
 
44
-    case CONFERENCE_WILL_JOIN: {
45
-        const { audioOnly } = store.getState()['features/base/conference'];
46
+        const { audioOnly, conference }
47
+            = getState()['features/base/conference'];
46
 
48
 
47
-        fullScreen = !audioOnly;
49
+        fullScreen = conference || action.conference ? !audioOnly : false;
48
         break;
50
         break;
49
     }
51
     }
50
 
52
 
52
     case CONFERENCE_LEFT:
54
     case CONFERENCE_LEFT:
53
         fullScreen = false;
55
         fullScreen = false;
54
         break;
56
         break;
55
-
56
-    case HIDE_DIALOG: {
57
-        const { audioOnly, conference }
58
-            = store.getState()['features/base/conference'];
59
-
60
-        fullScreen = conference ? !audioOnly : false;
61
-        break;
62
-    }
63
-
64
-    case SET_AUDIO_ONLY: {
65
-        const { conference } = store.getState()['features/base/conference'];
66
-
67
-        fullScreen = conference ? !action.audioOnly : false;
68
-        break;
69
-    }
70
     }
57
     }
71
 
58
 
72
     if (fullScreen !== null) {
59
     if (fullScreen !== null) {
75
                 console.warn(`Failed to set full screen mode: ${err}`));
62
                 console.warn(`Failed to set full screen mode: ${err}`));
76
     }
63
     }
77
 
64
 
78
-    return next(action);
65
+    return result;
79
 });
66
 });
80
 
67
 
81
 /**
68
 /**

+ 9
- 12
react/features/mobile/proximity/middleware.js Wyświetl plik

14
  * the screen and disable touch controls when an object is nearby. The
14
  * the screen and disable touch controls when an object is nearby. The
15
  * functionality is  enabled when a conference is in audio-only mode.
15
  * functionality is  enabled when a conference is in audio-only mode.
16
  *
16
  *
17
- * @param {Store} store - Redux store.
17
+ * @param {Store} store - The redux store.
18
  * @returns {Function}
18
  * @returns {Function}
19
  */
19
  */
20
-MiddlewareRegistry.register(store => next => action => {
21
-    switch (action.type) {
22
-    case CONFERENCE_JOINED: {
23
-        const { audioOnly } = store.getState()['features/base/conference'];
24
-
25
-        _setProximityEnabled(audioOnly);
26
-        break;
27
-    }
20
+MiddlewareRegistry.register(({ getState }) => next => action => {
21
+    const result = next(action);
28
 
22
 
23
+    switch (action.type) {
29
     case CONFERENCE_FAILED:
24
     case CONFERENCE_FAILED:
30
     case CONFERENCE_LEFT:
25
     case CONFERENCE_LEFT:
31
         _setProximityEnabled(false);
26
         _setProximityEnabled(false);
32
         break;
27
         break;
33
 
28
 
29
+    case CONFERENCE_JOINED:
34
     case SET_AUDIO_ONLY: {
30
     case SET_AUDIO_ONLY: {
35
-        const { conference } = store.getState()['features/base/conference'];
31
+        const { audioOnly, conference }
32
+            = getState()['features/base/conference'];
36
 
33
 
37
-        conference && _setProximityEnabled(action.audioOnly);
34
+        conference && _setProximityEnabled(audioOnly);
38
         break;
35
         break;
39
     }
36
     }
40
     }
37
     }
41
 
38
 
42
-    return next(action);
39
+    return result;
43
 });
40
 });
44
 
41
 
45
 /**
42
 /**

+ 55
- 14
react/features/toolbox/components/Toolbox.native.js Wyświetl plik

3
 import { connect } from 'react-redux';
3
 import { connect } from 'react-redux';
4
 
4
 
5
 import { toggleAudioOnly } from '../../base/conference';
5
 import { toggleAudioOnly } from '../../base/conference';
6
-import { MEDIA_TYPE, toggleCameraFacingMode } from '../../base/media';
6
+import {
7
+    MEDIA_TYPE,
8
+    setAudioMuted,
9
+    setVideoMuted,
10
+    toggleCameraFacingMode
11
+} from '../../base/media';
7
 import { Container } from '../../base/react';
12
 import { Container } from '../../base/react';
8
 import { ColorPalette } from '../../base/styles';
13
 import { ColorPalette } from '../../base/styles';
9
 import { beginRoomLockRequest } from '../../room-lock';
14
 import { beginRoomLockRequest } from '../../room-lock';
56
          */
61
          */
57
         _onShareRoom: React.PropTypes.func,
62
         _onShareRoom: React.PropTypes.func,
58
 
63
 
59
-        /**
60
-         * Handler for toggle audio.
61
-         */
62
-        _onToggleAudio: React.PropTypes.func,
63
-
64
         /**
64
         /**
65
          * Toggles the audio-only flag of the conference.
65
          * Toggles the audio-only flag of the conference.
66
          */
66
          */
72
          */
72
          */
73
         _onToggleCameraFacingMode: React.PropTypes.func,
73
         _onToggleCameraFacingMode: React.PropTypes.func,
74
 
74
 
75
-        /**
76
-         * Handler for toggling video.
77
-         */
78
-        _onToggleVideo: React.PropTypes.func,
79
-
80
         /**
75
         /**
81
          * Flag showing whether video is muted.
76
          * Flag showing whether video is muted.
82
          */
77
          */
85
         /**
80
         /**
86
          * Flag showing whether toolbar is visible.
81
          * Flag showing whether toolbar is visible.
87
          */
82
          */
88
-        _visible: React.PropTypes.bool
83
+        _visible: React.PropTypes.bool,
84
+
85
+        dispatch: React.PropTypes.func
89
     };
86
     };
90
 
87
 
88
+    /**
89
+     * Initializes a new {@code Toolbox} instance.
90
+     *
91
+     * @param {Object} props - The read-only React {@code Component} props with
92
+     * which the new instance is to be initialized.
93
+     */
94
+    constructor(props) {
95
+        super(props);
96
+
97
+        // Bind event handlers so they are only bound once per instance.
98
+        this._onToggleAudio = this._onToggleAudio.bind(this);
99
+        this._onToggleVideo = this._onToggleVideo.bind(this);
100
+    }
101
+
91
     /**
102
     /**
92
      * Implements React's {@link Component#render()}.
103
      * Implements React's {@link Component#render()}.
93
      *
104
      *
144
         };
155
         };
145
     }
156
     }
146
 
157
 
158
+    /**
159
+     * Dispatches an action to toggle the mute state of the audio/microphone.
160
+     *
161
+     * @private
162
+     * @returns {void}
163
+     */
164
+    _onToggleAudio() {
165
+        // The user sees the reality i.e. the state of base/tracks and intends
166
+        // to change reality by tapping on the respective button i.e. the user
167
+        // sets the state of base/media. Whether the user's intention will turn
168
+        // into reality is a whole different story which is of no concern to the
169
+        // tapping.
170
+        this.props.dispatch(setAudioMuted(!this.props._audioMuted));
171
+    }
172
+
173
+    /**
174
+     * Dispatches an action to toggle the mute state of the video/camera.
175
+     *
176
+     * @private
177
+     * @returns {void}
178
+     */
179
+    _onToggleVideo() {
180
+        // The user sees the reality i.e. the state of base/tracks and intends
181
+        // to change reality by tapping on the respective button i.e. the user
182
+        // sets the state of base/media. Whether the user's intention will turn
183
+        // into reality is a whole different story which is of no concern to the
184
+        // tapping.
185
+        this.props.dispatch(setVideoMuted(!this.props._videoMuted));
186
+    }
187
+
147
     /**
188
     /**
148
      * Renders the toolbar which contains the primary buttons such as hangup,
189
      * Renders the toolbar which contains the primary buttons such as hangup,
149
      * audio and video mute.
190
      * audio and video mute.
162
                 <ToolbarButton
203
                 <ToolbarButton
163
                     iconName = { audioButtonStyles.iconName }
204
                     iconName = { audioButtonStyles.iconName }
164
                     iconStyle = { audioButtonStyles.iconStyle }
205
                     iconStyle = { audioButtonStyles.iconStyle }
165
-                    onClick = { this.props._onToggleAudio }
206
+                    onClick = { this._onToggleAudio }
166
                     style = { audioButtonStyles.style } />
207
                     style = { audioButtonStyles.style } />
167
                 <ToolbarButton
208
                 <ToolbarButton
168
                     iconName = 'hangup'
209
                     iconName = 'hangup'
174
                     disabled = { this.props._audioOnly }
215
                     disabled = { this.props._audioOnly }
175
                     iconName = { videoButtonStyles.iconName }
216
                     iconName = { videoButtonStyles.iconName }
176
                     iconStyle = { videoButtonStyles.iconStyle }
217
                     iconStyle = { videoButtonStyles.iconStyle }
177
-                    onClick = { this.props._onToggleVideo }
218
+                    onClick = { this._onToggleVideo }
178
                     style = { videoButtonStyles.style } />
219
                     style = { videoButtonStyles.style } />
179
             </View>
220
             </View>
180
         );
221
         );

+ 5
- 24
react/features/toolbox/functions.native.js Wyświetl plik

3
 import type { Dispatch } from 'redux';
3
 import type { Dispatch } from 'redux';
4
 
4
 
5
 import { appNavigate } from '../app';
5
 import { appNavigate } from '../app';
6
-import { toggleAudioMuted, toggleVideoMuted } from '../base/media';
7
 import { getLocalAudioTrack, getLocalVideoTrack } from '../base/tracks';
6
 import { getLocalAudioTrack, getLocalVideoTrack } from '../base/tracks';
8
 
7
 
9
 /**
8
 /**
19
  */
18
  */
20
 export function abstractMapDispatchToProps(dispatch: Dispatch<*>): Object {
19
 export function abstractMapDispatchToProps(dispatch: Dispatch<*>): Object {
21
     return {
20
     return {
21
+        // Inject {@code dispatch} into the React Component's props in case it
22
+        // needs to dispatch an action in the redux store without
23
+        // {@code mapDispatchToProps}.
24
+        dispatch,
25
+
22
         /**
26
         /**
23
          * Dispatches action to leave the current conference.
27
          * Dispatches action to leave the current conference.
24
          *
28
          *
33
             // expression of (1) the lack of knowledge & (2) the desire to no
37
             // expression of (1) the lack of knowledge & (2) the desire to no
34
             // longer have a valid room name to join.
38
             // longer have a valid room name to join.
35
             dispatch(appNavigate(undefined));
39
             dispatch(appNavigate(undefined));
36
-        },
37
-
38
-        /**
39
-         * Dispatches an action to toggle the mute state of the
40
-         * audio/microphone.
41
-         *
42
-         * @private
43
-         * @returns {Object} - Dispatched action.
44
-         * @type {Function}
45
-         */
46
-        _onToggleAudio() {
47
-            dispatch(toggleAudioMuted());
48
-        },
49
-
50
-        /**
51
-         * Dispatches an action to toggle the mute state of the video/camera.
52
-         *
53
-         * @private
54
-         * @returns {Object} - Dispatched action.
55
-         * @type {Function}
56
-         */
57
-        _onToggleVideo() {
58
-            dispatch(toggleVideoMuted());
59
         }
40
         }
60
     };
41
     };
61
 }
42
 }

Ładowanie…
Anuluj
Zapisz