Browse Source

Fix toolbar's mute buttons when starting muted

The toolbar's mute buttons depict respective features/base/media states.
However, (un)muting is practically carried out by features/base/tracks.
When the mobile app enters a conference configured to invite the joining
participant to mute themselves, the tracks would be muted but the
toolbar's mute buttons would not reflect that.
master
Lyubomir Marinov 9 years ago
parent
commit
4997ae79e3

+ 1
- 1
react/features/base/lib-jitsi-meet/actions.js View File

34
  */
34
  */
35
 export function initLib() {
35
 export function initLib() {
36
     return (dispatch, getState) => {
36
     return (dispatch, getState) => {
37
-        const config = getState()['features/base/lib'].config;
37
+        const config = getState()['features/base/lib-jitsi-meet'].config;
38
 
38
 
39
         if (!config) {
39
         if (!config) {
40
             throw new Error('Cannot initialize lib-jitsi-meet without config');
40
             throw new Error('Cannot initialize lib-jitsi-meet without config');

+ 6
- 9
react/features/base/lib-jitsi-meet/middleware.js View File

19
 MiddlewareRegistry.register(store => next => action => {
19
 MiddlewareRegistry.register(store => next => action => {
20
     switch (action.type) {
20
     switch (action.type) {
21
     case PARTICIPANT_LEFT:
21
     case PARTICIPANT_LEFT:
22
-        if (action.participant.local) {
23
-            store.dispatch(disposeLib());
24
-        }
22
+        action.participant.local && store.dispatch(disposeLib());
25
         break;
23
         break;
26
 
24
 
27
     case SET_CONFIG: {
25
     case SET_CONFIG: {
28
         const { dispatch, getState } = store;
26
         const { dispatch, getState } = store;
29
-        const libInitialized = getState()['features/base/lib'].initialized;
27
+        const initialized
28
+            = getState()['features/base/lib-jitsi-meet'].initialized;
30
 
29
 
31
         // XXX If we already have config, that means new config is coming, which
30
         // XXX If we already have config, that means new config is coming, which
32
         // means that we should dispose instance of lib initialized with
31
         // means that we should dispose instance of lib initialized with
33
         // previous config first.
32
         // previous config first.
34
         // TODO Currently 'disposeLib' actually does not dispose lib-jitsi-meet.
33
         // TODO Currently 'disposeLib' actually does not dispose lib-jitsi-meet.
35
         // This functionality should be implemented.
34
         // This functionality should be implemented.
36
-        const promise = libInitialized
37
-            ? dispatch(disposeLib())
38
-            : Promise.resolve();
35
+        const promise
36
+            = initialized ? dispatch(disposeLib()) : Promise.resolve();
39
 
37
 
40
-        promise
41
-            .then(dispatch(initLib()));
38
+        promise.then(dispatch(initLib()));
42
 
39
 
43
         break;
40
         break;
44
     }
41
     }

+ 2
- 2
react/features/base/lib-jitsi-meet/reducer.js View File

8
 } from './actionTypes';
8
 } from './actionTypes';
9
 
9
 
10
 /**
10
 /**
11
- * Initial state of 'features/base/lib'.
11
+ * Initial state of 'features/base/lib-jitsi-meet'.
12
  *
12
  *
13
  * @type {{
13
  * @type {{
14
  *      initializationError: null,
14
  *      initializationError: null,
31
 };
31
 };
32
 
32
 
33
 ReducerRegistry.register(
33
 ReducerRegistry.register(
34
-    'features/base/lib',
34
+    'features/base/lib-jitsi-meet',
35
     (state = INITIAL_STATE, action) => {
35
     (state = INITIAL_STATE, action) => {
36
         switch (action.type) {
36
         switch (action.type) {
37
         case LIB_DISPOSED:
37
         case LIB_DISPOSED:

+ 4
- 9
react/features/base/media/middleware.js View File

42
     const { dispatch, getState } = store;
42
     const { dispatch, getState } = store;
43
     const state = getState()['features/base/media'];
43
     const state = getState()['features/base/media'];
44
 
44
 
45
-    if (state.audio.muted) {
46
-        dispatch(audioMutedChanged(false));
47
-    }
48
-    if (state.video.facingMode !== CAMERA_FACING_MODE.USER) {
49
-        dispatch(cameraFacingModeChanged(CAMERA_FACING_MODE.USER));
50
-    }
51
-    if (state.video.muted) {
52
-        dispatch(videoMutedChanged(false));
53
-    }
45
+    state.audio.muted && dispatch(audioMutedChanged(false));
46
+    (state.video.facingMode !== CAMERA_FACING_MODE.USER)
47
+        && dispatch(cameraFacingModeChanged(CAMERA_FACING_MODE.USER));
48
+    state.video.muted && dispatch(videoMutedChanged(false));
54
 }
49
 }
55
 
50
 
56
 /**
51
 /**

+ 8
- 4
react/features/base/tracks/functions.js View File

72
 }
72
 }
73
 
73
 
74
 /**
74
 /**
75
- * Mute or unmute local track if any.
75
+ * Mutes or unmutes a specific <tt>JitsiLocalTrack</tt>. If the muted state of
76
+ * the specified <tt>track</tt> is already in accord with the specified
77
+ * <tt>muted</tt> value, then does nothing.
76
  *
78
  *
77
- * @param {JitsiLocalTrack} track - Track instance.
78
- * @param {boolean} muted - If audio stream should be muted or unmuted.
79
+ * @param {JitsiLocalTrack} track - The <tt>JitsiLocalTrack</tt> to mute or
80
+ * unmute.
81
+ * @param {boolean} muted - If the specified <tt>track</tt> is to be muted, then
82
+ * <tt>true</tt>; otherwise, <tt>false</tt>.
79
  * @returns {Promise}
83
  * @returns {Promise}
80
  */
84
  */
81
 export function setTrackMuted(track, muted) {
85
 export function setTrackMuted(track, muted) {
82
-    if (!track) {
86
+    if (track.isMuted() === muted) {
83
         return Promise.resolve();
87
         return Promise.resolve();
84
     }
88
     }
85
 
89
 

+ 84
- 3
react/features/base/tracks/middleware.js View File

4
 } from '../lib-jitsi-meet';
4
 } from '../lib-jitsi-meet';
5
 import {
5
 import {
6
     AUDIO_MUTED_CHANGED,
6
     AUDIO_MUTED_CHANGED,
7
+    audioMutedChanged,
7
     CAMERA_FACING_MODE_CHANGED,
8
     CAMERA_FACING_MODE_CHANGED,
8
     MEDIA_TYPE,
9
     MEDIA_TYPE,
9
-    VIDEO_MUTED_CHANGED
10
+    VIDEO_MUTED_CHANGED,
11
+    videoMutedChanged
10
 } from '../media';
12
 } from '../media';
11
 import { MiddlewareRegistry } from '../redux';
13
 import { MiddlewareRegistry } from '../redux';
12
 
14
 
14
     createLocalTracks,
16
     createLocalTracks,
15
     destroyLocalTracks
17
     destroyLocalTracks
16
 } from './actions';
18
 } from './actions';
19
+import { TRACK_UPDATED } from './actionTypes';
17
 import {
20
 import {
18
     getLocalTrack,
21
     getLocalTrack,
19
     setTrackMuted
22
     setTrackMuted
50
         store.dispatch(destroyLocalTracks());
53
         store.dispatch(destroyLocalTracks());
51
         break;
54
         break;
52
 
55
 
56
+    case TRACK_UPDATED:
57
+        return _trackUpdated(store, next, action);
58
+
53
     case VIDEO_MUTED_CHANGED:
59
     case VIDEO_MUTED_CHANGED:
54
         _mutedChanged(store, action, MEDIA_TYPE.VIDEO);
60
         _mutedChanged(store, action, MEDIA_TYPE.VIDEO);
55
         break;
61
         break;
58
     return next(action);
64
     return next(action);
59
 });
65
 });
60
 
66
 
67
+/**
68
+ * Gets the local track associated with a specific <tt>MEDIA_TYPE</tt> in a
69
+ * specific Redux store.
70
+ *
71
+ * @param {Store} store - The Redux store from which the local track associated
72
+ * with the specified <tt>mediaType</tt> is to be retrieved.
73
+ * @param {MEDIA_TYPE} mediaType - The <tt>MEDIA_TYPE</tt> of the local track to
74
+ * be retrieved from the specified <tt>store</tt>.
75
+ * @private
76
+ * @returns {Track} The local <tt>Track</tt> associated with the specified
77
+ * <tt>mediaType</tt> in the specified <tt>store</tt>.
78
+ */
79
+function _getLocalTrack(store, mediaType) {
80
+    return getLocalTrack(store.getState()['features/base/tracks'], mediaType);
81
+}
82
+
61
 /**
83
 /**
62
  * Mutes or unmutes a local track with a specific media type.
84
  * Mutes or unmutes a local track with a specific media type.
63
  *
85
  *
70
  * @returns {void}
92
  * @returns {void}
71
  */
93
  */
72
 function _mutedChanged(store, action, mediaType) {
94
 function _mutedChanged(store, action, mediaType) {
73
-    const tracks = store.getState()['features/base/tracks'];
74
-    const localTrack = getLocalTrack(tracks, mediaType);
95
+    const localTrack = _getLocalTrack(store, mediaType);
75
 
96
 
76
     localTrack && setTrackMuted(localTrack.jitsiTrack, action.muted);
97
     localTrack && setTrackMuted(localTrack.jitsiTrack, action.muted);
77
 }
98
 }
99
+
100
+/**
101
+ * Intercepts the action <tt>TRACK_UPDATED</tt> in order to synchronize the
102
+ * muted states of the local tracks of features/base/tracks with the muted
103
+ * states of features/base/media.
104
+ *
105
+ * @param {Store} store - The Redux store in which the specified <tt>action</tt>
106
+ * is being dispatched.
107
+ * @param {Dispatch} next - The Redux dispatch function to dispatch the
108
+ * specified <tt>action</tt> to the specified <tt>store</tt>.
109
+ * @param {Action} action - The Redux action <tt>TRACK_UPDATED</tt> which is
110
+ * being dispatched in the specified <tt>store</tt>.
111
+ * @private
112
+ * @returns {void}
113
+ */
114
+function _trackUpdated(store, next, action) {
115
+    // Determine the muted state of the local track before the update.
116
+    const track = action.track;
117
+    let mediaType;
118
+    let oldMuted;
119
+
120
+    if ('muted' in track) {
121
+        // XXX The return value of JitsiTrack.getType() is of type MEDIA_TYPE
122
+        // that happens to be compatible with the type MEDIA_TYPE defined by
123
+        // jitsi-meet-react.
124
+        mediaType = track.jitsiTrack.getType();
125
+
126
+        const localTrack = _getLocalTrack(store, mediaType);
127
+
128
+        if (localTrack) {
129
+            oldMuted = localTrack.muted;
130
+        }
131
+    }
132
+
133
+    const result = next(action);
134
+
135
+    if (typeof oldMuted !== 'undefined') {
136
+        // Determine the muted state of the local track after the update. If the
137
+        // muted states before and after the update differ, then the respective
138
+        // media state should by synchronized.
139
+        const localTrack = _getLocalTrack(store, mediaType);
140
+
141
+        if (localTrack) {
142
+            const newMuted = localTrack.muted;
143
+
144
+            if (oldMuted !== newMuted) {
145
+                switch (mediaType) {
146
+                case MEDIA_TYPE.AUDIO:
147
+                    store.dispatch(audioMutedChanged(newMuted));
148
+                    break;
149
+                case MEDIA_TYPE.VIDEO:
150
+                    store.dispatch(videoMutedChanged(newMuted));
151
+                    break;
152
+                }
153
+            }
154
+        }
155
+    }
156
+
157
+    return result;
158
+}

+ 2
- 3
react/features/largeVideo/middleware.js View File

49
                     action.track.jitsiTrack);
49
                     action.track.jitsiTrack);
50
             const participantId = state['features/largeVideo'].participantId;
50
             const participantId = state['features/largeVideo'].participantId;
51
 
51
 
52
-            if (track.participantId === participantId) {
53
-                store.dispatch(selectParticipant());
54
-            }
52
+            (track.participantId === participantId)
53
+                && store.dispatch(selectParticipant());
55
         }
54
         }
56
         break;
55
         break;
57
     }
56
     }

Loading…
Cancel
Save